{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3D Alexandria Database\n",
    "\n",
    "\n",
    "![alexandria_3d](images/alexandria_3d_database.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "import os\n",
    "import logging\n",
    "from glob import glob\n",
    "import shutil\n",
    "import time\n",
    "\n",
    "import numpy as np\n",
    "from pyarrow import compute as pc\n",
    "\n",
    "from parquetdb.core.parquetdb import LoadConfig, NormalizeConfig\n",
    "from parquetdb.utils.general_utils import timeit\n",
    "from parquetdb import ParquetDB, config\n",
    "from parquetdb.utils.external_utils import download_alexandria_3d_database\n",
    "\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setup data directories"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "base_dir = os.path.join(config.data_dir, \"external\", \"alexandria\", \"AlexandriaDB\")\n",
    "benchmark_dir = os.path.join(config.data_dir, \"benchmarks\", \"alexandria\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Download the database\n",
    "\n",
    "Lets download the database"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: download_alexandria_database\n",
      "Database downloaded already. Skipping download.\n",
      "Done with task: download_alexandria_database\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Z:\\data\\parquetdb\\data\\external\\alexandria\\uncompressed\n"
     ]
    }
   ],
   "source": [
    "def download_alexandria_database(base_dir, from_scratch=False):\n",
    "    print(\"Starting task: download_alexandria_database\")\n",
    "    if from_scratch and os.path.exists(base_dir):\n",
    "        print(f\"Removing existing directory: {base_dir}\")\n",
    "        shutil.rmtree(base_dir, ignore_errors=True)\n",
    "\n",
    "    # Here we download the database and save it to the data directory\n",
    "    output_dir = os.path.join(config.data_dir, \"external\", \"alexandria\")\n",
    "    alexandria_dir = download_alexandria_3d_database(output_dir, n_cores=8)\n",
    "    print(\"Done with task: download_alexandria_database\")\n",
    "    print(\"-\" * 200)\n",
    "    return alexandria_dir\n",
    "\n",
    "\n",
    "alexandria_dir = download_alexandria_database(base_dir, from_scratch=False)\n",
    "print(alexandria_dir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating the database\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "============================================================\n",
      "PARQUETDB SUMMARY\n",
      "============================================================\n",
      "Database path: Z:\\data\\parquetdb\\data\\external\\alexandria\\AlexandriaDB\\alexandria_3D\n",
      "\n",
      "• Number of columns: 1\n",
      "• Number of rows: 0\n",
      "• Number of files: 1\n",
      "• Number of rows per file: [0]\n",
      "• Number of row groups per file: [1]\n",
      "• Serialized metadata size per file: [312] Bytes\n",
      "\n",
      "############################################################\n",
      "METADATA\n",
      "############################################################\n",
      "\n",
      "############################################################\n",
      "COLUMN DETAILS\n",
      "############################################################\n",
      "• Columns:\n",
      "    - id\n",
      "\n"
     ]
    }
   ],
   "source": [
    "db = ParquetDB(db_path=os.path.join(base_dir, \"alexandria_3D\"))\n",
    "print(db)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lets Define some dictionaries to store some benchmark results\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "benchmark_dict = {\n",
    "    \"create_times\": [],\n",
    "    \"json_load_times\": [],\n",
    "    \"n_rows_per_file\": [],\n",
    "}\n",
    "\n",
    "task_benchmark_dict = {\"task_names\": [], \"task_times\": []}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Inputing the data\n",
    "\n",
    "Here I am just iterating over the json files and creating the database. I am also storing how long it takes to load each json file, how many materials, and how long it takes to input the data into the database.\n",
    "\n",
    "This dataset is rather large, so you may have to choose the normalization parameters depending on how much RAM you have. If you do not have enough tweak the `batch_size`, `batch_readahead`, `fragment_readahead` parameters.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: create_database_if_empty\n",
      "The dataset does not exist. Creating it.\n",
      "Processing file: alexandria_001.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 9.207536935806274\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_002.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 9.03726840019226\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_003.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.272280693054199\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_004.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.3968799114227295\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_005.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 9.731169700622559\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_006.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.279998540878296\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_007.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.452792167663574\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_008.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.5389344692230225\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_009.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 12.014537334442139\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_010.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.618973016738892\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_011.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 8.03697943687439\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_012.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.7988600730896\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_013.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.983482122421265\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_014.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.620621919631958\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_015.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.09317684173584\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_016.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.633606433868408\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_017.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.403124570846558\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_018.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.627993822097778\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_019.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.117793560028076\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_020.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.894531011581421\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_021.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.83626651763916\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_022.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.791656732559204\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_023.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.708625555038452\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_024.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 8.351858377456665\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_025.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.344949007034302\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_026.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 27.566998958587646\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_027.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.999422073364258\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_028.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 8.236054182052612\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_029.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 8.136978387832642\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_030.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.855477571487427\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_031.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.7916247844696045\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_032.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.601974010467529\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_033.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.663681983947754\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_034.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.94143009185791\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_035.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.299615859985352\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_036.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.486094951629639\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_037.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 8.335729360580444\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_038.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.945127248764038\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_039.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.50490403175354\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_040.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.409191131591797\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_041.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.5053534507751465\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_042.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 7.061246871948242\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_043.json\n",
      "Number of materials: 100000\n",
      "Time taken to create dataset: 6.405843496322632\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Processing file: alexandria_044.json\n",
      "Number of materials: 89295\n",
      "Time taken to create dataset: 5.768043756484985\n",
      "----------------------------------------------------------------------------------------------------\n",
      "Done with task: create_database_if_empty\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "def create_database_if_empty(db, alexandria_dir, normalize_config=NormalizeConfig()):\n",
    "    \"\"\"_summary_\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    db : ParquetDB Instance\n",
    "        The database instance to create the dataset on.\n",
    "    alexandria_dir : str\n",
    "        The directory containing the json files to input into the database.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    _type_\n",
    "        _description_\n",
    "    \"\"\"\n",
    "    print(\"Starting task: create_database_if_empty\")\n",
    "\n",
    "    start_time = time.time()\n",
    "\n",
    "    json_load_times = []\n",
    "    create_times = []\n",
    "    n_materials_per_file = []\n",
    "    if db.is_empty():\n",
    "        print(\"The dataset does not exist. Creating it.\")\n",
    "        json_files = glob(os.path.join(alexandria_dir, \"*.json\"))\n",
    "        for json_file in json_files[:]:\n",
    "\n",
    "            start_time = time.time()\n",
    "            with open(json_file, \"r\") as f:\n",
    "                data = json.load(f)\n",
    "            json_load_time = time.time() - start_time\n",
    "\n",
    "            base_name = os.path.basename(json_file)\n",
    "            n_materials = len(data[\"entries\"])\n",
    "            print(f\"Processing file: {base_name}\")\n",
    "            print(f\"Number of materials: {n_materials}\")\n",
    "            try:\n",
    "                # Since we are importing alot of data it is best\n",
    "                # to normalize the database afterwards\n",
    "                start_time = time.time()\n",
    "                db.create(\n",
    "                    data[\"entries\"],\n",
    "                    normalize_dataset=False,\n",
    "                    normalize_config=normalize_config,\n",
    "                )\n",
    "                create_time = time.time() - start_time\n",
    "\n",
    "                create_times.append(create_time)\n",
    "                n_materials_per_file.append(n_materials)\n",
    "                json_load_times.append(json_load_time)\n",
    "\n",
    "            except Exception as e:\n",
    "                print(e)\n",
    "\n",
    "            data = None\n",
    "\n",
    "            print(f\"Time taken to create dataset: {time.time() - start_time}\")\n",
    "            print(\"-\" * 100)\n",
    "\n",
    "    print(\"Done with task: create_database_if_empty\")\n",
    "    print(\"-\" * 200)\n",
    "    return json_load_times, create_times, n_materials_per_file\n",
    "\n",
    "\n",
    "normalize_config = NormalizeConfig(\n",
    "    load_format=\"batches\",  # Uses the batch generator to normalize\n",
    "    batch_readahead=4,  # Controls the number of batches to load in memory a head of time. This will have impacts on amount of RAM consumed\n",
    "    fragment_readahead=2,  # Controls the number of files to load in memory ahead of time. This will have impacts on amount of RAM consumed\n",
    "    batch_size=100000,  # Controls the batchsize when to use when normalizing. This will have impacts on amount of RAM consumed\n",
    "    max_rows_per_file=100000,  # Controls the max number of rows per parquet file\n",
    "    max_rows_per_group=100000,\n",
    ")  # Controls the max number of rows per group parquet\n",
    "\n",
    "\n",
    "json_load_times, create_times, n_materials_per_file = create_database_if_empty(\n",
    "    db, alexandria_dir, normalize_config=normalize_config\n",
    ")\n",
    "\n",
    "benchmark_dict[\"create_times\"] = create_times\n",
    "benchmark_dict[\"json_load_times\"] = json_load_times\n",
    "benchmark_dict[\"n_rows_per_file\"] = n_materials_per_file"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Normalizing the dataset\n",
    "\n",
    "It is best practive to normalize the dataset after all the data has been inputed. This will optimize the performance of the database.\n",
    "\n",
    "First let's see how the data is distributed in the row groups.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "============================================================\n",
      "PARQUETDB SUMMARY\n",
      "============================================================\n",
      "Database path: Z:\\data\\parquetdb\\data\\external\\alexandria\\AlexandriaDB\\alexandria_3D\n",
      "\n",
      "• Number of columns: 128\n",
      "• Number of rows: 4389295\n",
      "• Number of files: 44\n",
      "• Number of rows per file: [100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 89295, 100000, 100000, 100000, 100000, 100000]\n",
      "• Number of row groups per file: [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 4, 4, 4, 4, 4]\n",
      "• Number of rows per row group per file: \n",
      "    - alexandria_3D_0.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_1.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_10.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_11.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_12.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_13.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_14.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_15.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_16.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_17.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_18.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_19.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_2.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_20.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_21.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_22.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_23.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_24.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_25.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_26.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_27.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_28.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_29.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_3.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_30.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_31.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_32.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_33.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_34.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_35.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_36.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_37.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_38.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_39.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_4.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_40.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_41.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_42.parquet:\n",
      "        - Row group 0: 100000 rows\n",
      "    - alexandria_3D_43.parquet:\n",
      "        - Row group 0: 89295 rows\n",
      "    - alexandria_3D_5.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_6.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_7.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_8.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "    - alexandria_3D_9.parquet:\n",
      "        - Row group 0: 32768 rows\n",
      "        - Row group 1: 32768 rows\n",
      "        - Row group 2: 32768 rows\n",
      "        - Row group 3: 1696 rows\n",
      "• Serialized metadata size per file: [74101, 77444, 77856, 77696, 78981, 76117, 74681, 75387, 77761, 77151, 73789, 78065, 76137, 75769, 77500, 72899, 79079, 77137, 30983, 31079, 31034, 31038, 31521, 75599, 31495, 30344, 31060, 31337, 31354, 31177, 31163, 31191, 30452, 30605, 75367, 30766, 31097, 30715, 30329, 74876, 76781, 78952, 78372, 77480] Bytes\n",
      "\n",
      "############################################################\n",
      "METADATA\n",
      "############################################################\n",
      "\n",
      "############################################################\n",
      "COLUMN DETAILS\n",
      "############################################################\n",
      "\n"
     ]
    }
   ],
   "source": [
    "summary = db.summary(show_row_group_metadata=True)\n",
    "print(summary)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check the file size of the parquet files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "alexandria_3D_0.parquet: 63.217278480529785 MB\n",
      "alexandria_3D_1.parquet: 66.39281272888184 MB\n",
      "alexandria_3D_10.parquet: 67.79165077209473 MB\n",
      "alexandria_3D_11.parquet: 76.40940952301025 MB\n",
      "alexandria_3D_12.parquet: 64.72634792327881 MB\n",
      "alexandria_3D_13.parquet: 61.073683738708496 MB\n",
      "alexandria_3D_14.parquet: 59.82237529754639 MB\n",
      "alexandria_3D_15.parquet: 59.66804218292236 MB\n",
      "alexandria_3D_16.parquet: 79.35534191131592 MB\n",
      "alexandria_3D_17.parquet: 65.30797958374023 MB\n",
      "alexandria_3D_18.parquet: 53.305752754211426 MB\n",
      "alexandria_3D_19.parquet: 67.49996185302734 MB\n",
      "alexandria_3D_2.parquet: 80.63626098632812 MB\n",
      "alexandria_3D_20.parquet: 60.81020164489746 MB\n",
      "alexandria_3D_21.parquet: 71.9999008178711 MB\n",
      "alexandria_3D_22.parquet: 57.005184173583984 MB\n",
      "alexandria_3D_23.parquet: 76.82518005371094 MB\n",
      "alexandria_3D_24.parquet: 69.84022235870361 MB\n",
      "alexandria_3D_25.parquet: 73.2688102722168 MB\n",
      "alexandria_3D_26.parquet: 70.60673236846924 MB\n",
      "alexandria_3D_27.parquet: 79.58608531951904 MB\n",
      "alexandria_3D_28.parquet: 79.32598686218262 MB\n",
      "alexandria_3D_29.parquet: 72.01288318634033 MB\n",
      "alexandria_3D_3.parquet: 58.68510627746582 MB\n",
      "alexandria_3D_30.parquet: 68.60778427124023 MB\n",
      "alexandria_3D_31.parquet: 53.06931400299072 MB\n",
      "alexandria_3D_32.parquet: 53.88803291320801 MB\n",
      "alexandria_3D_33.parquet: 73.62857913970947 MB\n",
      "alexandria_3D_34.parquet: 63.31537055969238 MB\n",
      "alexandria_3D_35.parquet: 51.56621837615967 MB\n",
      "alexandria_3D_36.parquet: 80.69254112243652 MB\n",
      "alexandria_3D_37.parquet: 59.53824043273926 MB\n",
      "alexandria_3D_38.parquet: 64.71589279174805 MB\n",
      "alexandria_3D_39.parquet: 66.9590711593628 MB\n",
      "alexandria_3D_4.parquet: 58.02934169769287 MB\n",
      "alexandria_3D_40.parquet: 66.78332233428955 MB\n",
      "alexandria_3D_41.parquet: 61.57388782501221 MB\n",
      "alexandria_3D_42.parquet: 52.7365026473999 MB\n",
      "alexandria_3D_43.parquet: 46.13230228424072 MB\n",
      "alexandria_3D_5.parquet: 72.92802429199219 MB\n",
      "alexandria_3D_6.parquet: 66.0786542892456 MB\n",
      "alexandria_3D_7.parquet: 71.52147197723389 MB\n",
      "alexandria_3D_8.parquet: 68.42291927337646 MB\n",
      "alexandria_3D_9.parquet: 73.67225074768066 MB\n"
     ]
    }
   ],
   "source": [
    "def list_file_sizes(directory, in_MB=True):\n",
    "    \"\"\"Lists the size of files in a directory.\n",
    "\n",
    "    Args:\n",
    "      directory: The path to the directory.\n",
    "    \"\"\"\n",
    "    file_sizes = {}\n",
    "    for filename in os.listdir(directory):\n",
    "        file_path = os.path.join(directory, filename)\n",
    "        if os.path.isfile(file_path):\n",
    "            file_size = os.path.getsize(file_path)\n",
    "            if in_MB:\n",
    "                file_size = file_size / (1024 * 1024)\n",
    "            file_sizes[filename] = file_size\n",
    "    return file_sizes\n",
    "\n",
    "\n",
    "file_sizes = list_file_sizes(db.db_path)\n",
    "\n",
    "for file, size in file_sizes.items():\n",
    "    print(f\"{file}: {size} MB\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's also check the size of the row groups.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "alexandria_3D_0.parquet\n",
      "     0: 33.88526916503906 MB\n",
      "     1: 28.67838764190674 MB\n",
      "     2: 26.826565742492676 MB\n",
      "     3: 1.0584754943847656 MB\n",
      "alexandria_3D_1.parquet\n",
      "     0: 23.262088775634766 MB\n",
      "     1: 34.650197982788086 MB\n",
      "     2: 36.09531307220459 MB\n",
      "     3: 1.8985786437988281 MB\n",
      "alexandria_3D_10.parquet\n",
      "     0: 28.755844116210938 MB\n",
      "     1: 31.349617958068848 MB\n",
      "     2: 33.02553176879883 MB\n",
      "     3: 1.9675817489624023 MB\n",
      "alexandria_3D_11.parquet\n",
      "     0: 48.49870491027832 MB\n",
      "     1: 29.866143226623535 MB\n",
      "     2: 28.96322250366211 MB\n",
      "     3: 1.456308364868164 MB\n",
      "alexandria_3D_12.parquet\n",
      "     0: 35.41706848144531 MB\n",
      "     1: 27.881027221679688 MB\n",
      "     2: 27.899497985839844 MB\n",
      "     3: 1.2672271728515625 MB\n",
      "alexandria_3D_13.parquet\n",
      "     0: 29.536629676818848 MB\n",
      "     1: 28.44379234313965 MB\n",
      "     2: 27.21775722503662 MB\n",
      "     3: 1.3715496063232422 MB\n",
      "alexandria_3D_14.parquet\n",
      "     0: 32.75925064086914 MB\n",
      "     1: 25.701278686523438 MB\n",
      "     2: 24.80800437927246 MB\n",
      "     3: 1.0945501327514648 MB\n",
      "alexandria_3D_15.parquet\n",
      "     0: 28.813363075256348 MB\n",
      "     1: 24.955053329467773 MB\n",
      "     2: 27.343029022216797 MB\n",
      "     3: 2.002194404602051 MB\n",
      "alexandria_3D_16.parquet\n",
      "     0: 38.87716007232666 MB\n",
      "     1: 44.16834259033203 MB\n",
      "     2: 30.809864044189453 MB\n",
      "     3: 1.4979143142700195 MB\n",
      "alexandria_3D_17.parquet\n",
      "     0: 31.438282012939453 MB\n",
      "     1: 29.75895881652832 MB\n",
      "     2: 31.682196617126465 MB\n",
      "     3: 1.9960041046142578 MB\n",
      "alexandria_3D_18.parquet\n",
      "     0: 26.820265769958496 MB\n",
      "     1: 21.677895545959473 MB\n",
      "     2: 24.17652416229248 MB\n",
      "     3: 1.1478967666625977 MB\n",
      "alexandria_3D_19.parquet\n",
      "     0: 30.522936820983887 MB\n",
      "     1: 37.90152645111084 MB\n",
      "     2: 27.28691577911377 MB\n",
      "     3: 1.362447738647461 MB\n",
      "alexandria_3D_2.parquet\n",
      "     0: 39.840396881103516 MB\n",
      "     1: 35.17914295196533 MB\n",
      "     2: 37.78933525085449 MB\n",
      "     3: 1.4440546035766602 MB\n",
      "alexandria_3D_20.parquet\n",
      "     0: 28.389055252075195 MB\n",
      "     1: 26.526031494140625 MB\n",
      "     2: 30.0849027633667 MB\n",
      "     3: 1.1245336532592773 MB\n",
      "alexandria_3D_21.parquet\n",
      "     0: 26.3947114944458 MB\n",
      "     1: 39.86369228363037 MB\n",
      "     2: 34.58688449859619 MB\n",
      "     3: 1.5055503845214844 MB\n",
      "alexandria_3D_22.parquet\n",
      "     0: 30.08759593963623 MB\n",
      "     1: 24.752853393554688 MB\n",
      "     2: 23.644336700439453 MB\n",
      "     3: 1.2023286819458008 MB\n",
      "alexandria_3D_23.parquet\n",
      "     0: 33.71604251861572 MB\n",
      "     1: 43.66508960723877 MB\n",
      "     2: 33.232436180114746 MB\n",
      "     3: 1.5115013122558594 MB\n",
      "alexandria_3D_24.parquet\n",
      "     0: 33.69458198547363 MB\n",
      "     1: 29.915438652038574 MB\n",
      "     2: 33.283854484558105 MB\n",
      "     3: 2.087203025817871 MB\n",
      "alexandria_3D_25.parquet\n",
      "     0: 113.63787937164307 MB\n",
      "alexandria_3D_26.parquet\n",
      "     0: 110.95186138153076 MB\n",
      "alexandria_3D_27.parquet\n",
      "     0: 121.27318477630615 MB\n",
      "alexandria_3D_28.parquet\n",
      "     0: 120.9677734375 MB\n",
      "alexandria_3D_29.parquet\n",
      "     0: 114.41764545440674 MB\n",
      "alexandria_3D_3.parquet\n",
      "     0: 27.135764122009277 MB\n",
      "     1: 26.59963893890381 MB\n",
      "     2: 28.526336669921875 MB\n",
      "     3: 1.7803220748901367 MB\n",
      "alexandria_3D_30.parquet\n",
      "     0: 111.70868110656738 MB\n",
      "alexandria_3D_31.parquet\n",
      "     0: 87.3005952835083 MB\n",
      "alexandria_3D_32.parquet\n",
      "     0: 88.21440029144287 MB\n",
      "alexandria_3D_33.parquet\n",
      "     0: 115.94622802734375 MB\n",
      "alexandria_3D_34.parquet\n",
      "     0: 102.83384799957275 MB\n",
      "alexandria_3D_35.parquet\n",
      "     0: 86.06189823150635 MB\n",
      "alexandria_3D_36.parquet\n",
      "     0: 120.09446239471436 MB\n",
      "alexandria_3D_37.parquet\n",
      "     0: 95.56644344329834 MB\n",
      "alexandria_3D_38.parquet\n",
      "     0: 106.56142330169678 MB\n",
      "alexandria_3D_39.parquet\n",
      "     0: 106.53310775756836 MB\n",
      "alexandria_3D_4.parquet\n",
      "     0: 26.864155769348145 MB\n",
      "     1: 30.033101081848145 MB\n",
      "     2: 24.01892852783203 MB\n",
      "     3: 1.1299266815185547 MB\n",
      "alexandria_3D_40.parquet\n",
      "     0: 107.71124458312988 MB\n",
      "alexandria_3D_41.parquet\n",
      "     0: 98.69949913024902 MB\n",
      "alexandria_3D_42.parquet\n",
      "     0: 86.55539226531982 MB\n",
      "alexandria_3D_43.parquet\n",
      "     0: 76.38001537322998 MB\n",
      "alexandria_3D_5.parquet\n",
      "     0: 30.619487762451172 MB\n",
      "     1: 40.44719314575195 MB\n",
      "     2: 31.88987159729004 MB\n",
      "     3: 1.137807846069336 MB\n",
      "alexandria_3D_6.parquet\n",
      "     0: 28.624879837036133 MB\n",
      "     1: 27.89090061187744 MB\n",
      "     2: 35.02172374725342 MB\n",
      "     3: 1.4424219131469727 MB\n",
      "alexandria_3D_7.parquet\n",
      "     0: 43.56060314178467 MB\n",
      "     1: 27.994236946105957 MB\n",
      "     2: 29.434123039245605 MB\n",
      "     3: 1.6086492538452148 MB\n",
      "alexandria_3D_8.parquet\n",
      "     0: 28.378860473632812 MB\n",
      "     1: 33.01034450531006 MB\n",
      "     2: 35.88528060913086 MB\n",
      "     3: 1.7302274703979492 MB\n",
      "alexandria_3D_9.parquet\n",
      "     0: 42.97386932373047 MB\n",
      "     1: 33.387916564941406 MB\n",
      "     2: 26.984159469604492 MB\n",
      "     3: 1.7877273559570312 MB\n",
      "Average row group size: 36.577393547827455 MB\n"
     ]
    }
   ],
   "source": [
    "row_group_metadata_per_file = db.get_parquet_file_row_group_metadata_per_file(\n",
    "    as_dict=True\n",
    ")\n",
    "row_group_size_per_file = {}\n",
    "sum_row_group_size = 0\n",
    "num_row_groups = 0\n",
    "for file, row_group_metadata in row_group_metadata_per_file.items():\n",
    "    print(f\"{file}\")\n",
    "    row_group_size_per_file[file] = {}\n",
    "    for row_group, metadata in row_group_metadata.items():\n",
    "        row_group_size_per_file[file][row_group] = metadata[\"total_byte_size\"] / (\n",
    "            1024 * 1024\n",
    "        )\n",
    "        sum_row_group_size += row_group_size_per_file[file][row_group]\n",
    "        num_row_groups += 1\n",
    "        print(f\"     {row_group}: {row_group_size_per_file[file][row_group]} MB\")\n",
    "\n",
    "print(f\"Average row group size: {sum_row_group_size/num_row_groups} MB\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For the most optimal performance we should aim for 2GB per file and about 200-500MB per row group.\n",
    "\n",
    "Currently for a row group with 32,768 rows the size of the row group is ~30MB. To get to 200MB we should put 200MB/30MB more rows in the row group or ~200,000 rows.\n",
    "\n",
    "If each rowgroup is about 200MB at 200,000 rows then we should have 2GB/200MB = 10 row groups per file. or 2,000,000 rows per file. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: normalize_dataset\n",
      "Done with task: normalize_dataset\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "============================================================\n",
      "PARQUETDB SUMMARY\n",
      "============================================================\n",
      "Database path: Z:\\data\\parquetdb\\data\\external\\alexandria\\AlexandriaDB\\alexandria_3D\n",
      "\n",
      "• Number of columns: 128\n",
      "• Number of rows: 4389295\n",
      "• Number of files: 3\n",
      "• Number of rows per file: [2000000, 2000000, 389295]\n",
      "• Number of row groups per file: [10, 10, 2]\n",
      "• Number of rows per row group per file: \n",
      "    - alexandria_3D_0.parquet:\n",
      "        - Row group 0: 200000 rows\n",
      "        - Row group 1: 200000 rows\n",
      "        - Row group 2: 200000 rows\n",
      "        - Row group 3: 200000 rows\n",
      "        - Row group 4: 200000 rows\n",
      "        - Row group 5: 200000 rows\n",
      "        - Row group 6: 200000 rows\n",
      "        - Row group 7: 200000 rows\n",
      "        - Row group 8: 200000 rows\n",
      "        - Row group 9: 200000 rows\n",
      "    - alexandria_3D_1.parquet:\n",
      "        - Row group 0: 200000 rows\n",
      "        - Row group 1: 200000 rows\n",
      "        - Row group 2: 200000 rows\n",
      "        - Row group 3: 200000 rows\n",
      "        - Row group 4: 200000 rows\n",
      "        - Row group 5: 200000 rows\n",
      "        - Row group 6: 200000 rows\n",
      "        - Row group 7: 200000 rows\n",
      "        - Row group 8: 200000 rows\n",
      "        - Row group 9: 200000 rows\n",
      "    - alexandria_3D_2.parquet:\n",
      "        - Row group 0: 200000 rows\n",
      "        - Row group 1: 189295 rows\n",
      "• Serialized metadata size per file: [180510, 178802, 48142] Bytes\n",
      "\n",
      "############################################################\n",
      "METADATA\n",
      "############################################################\n",
      "\n",
      "############################################################\n",
      "COLUMN DETAILS\n",
      "############################################################\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def normalize_dataset(db, normalize_config=NormalizeConfig()):\n",
    "    task_name = \"normalize_dataset\"\n",
    "    print(\"Starting task: normalize_dataset\")\n",
    "\n",
    "    db.normalize(normalize_config=normalize_config)\n",
    "    print(\"Done with task: normalize_dataset\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "normalize_config = NormalizeConfig(\n",
    "    load_format=\"batches\",  # Uses the batch generator to normalize\n",
    "    batch_readahead=4,  # Controls the number of batches to load in memory a head of time. This will have impacts on amount of RAM consumed\n",
    "    fragment_readahead=1,  # Controls the number of files to load in memory ahead of time. This will have impacts on amount of RAM consumed\n",
    "    batch_size=10000,  # Controls the batchsize when to use when normalizing. This will have impacts on amount of RAM consumed\n",
    "    max_rows_per_file=2000000,  # Controls the max number of rows per parquet file\n",
    "    max_rows_per_group=200000,\n",
    "    min_rows_per_group=200000,\n",
    ")  # Controls the max number of rows per group parquet file\n",
    "normalize_dataset(db, normalize_config=normalize_config)\n",
    "print(db.summary(show_row_group_metadata=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check the file sizes and row group sizes again."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "alexandria_3D_0.parquet: 1261.1049909591675 MB\n",
      "alexandria_3D_1.parquet: 1251.4470014572144 MB\n",
      "alexandria_3D_2.parquet: 254.18889236450195 MB\n",
      "alexandria_3D_0.parquet\n",
      "     0: 203.45607089996338 MB\n",
      "     1: 217.69878768920898 MB\n",
      "     2: 197.38053512573242 MB\n",
      "     3: 187.29719257354736 MB\n",
      "     4: 227.97186374664307 MB\n",
      "     5: 192.6089096069336 MB\n",
      "     6: 216.6963243484497 MB\n",
      "     7: 198.1317253112793 MB\n",
      "     8: 226.02880668640137 MB\n",
      "     9: 226.7027463912964 MB\n",
      "alexandria_3D_1.parquet\n",
      "     0: 244.55265712738037 MB\n",
      "     1: 210.91666316986084 MB\n",
      "     2: 204.90382862091064 MB\n",
      "     3: 204.14434432983398 MB\n",
      "     4: 192.36827659606934 MB\n",
      "     5: 217.43347454071045 MB\n",
      "     6: 215.3526430130005 MB\n",
      "     7: 201.5632438659668 MB\n",
      "     8: 189.40411949157715 MB\n",
      "     9: 200.09713077545166 MB\n",
      "alexandria_3D_2.parquet\n",
      "     0: 208.74722480773926 MB\n",
      "     1: 206.02736282348633 MB\n",
      "Average row group size: 208.6129059791565 MB\n"
     ]
    }
   ],
   "source": [
    "file_sizes = list_file_sizes(db.db_path)\n",
    "\n",
    "for file, size in file_sizes.items():\n",
    "    print(f\"{file}: {size} MB\")\n",
    "\n",
    "\n",
    "row_group_metadata_per_file = db.get_parquet_file_row_group_metadata_per_file(\n",
    "    as_dict=True\n",
    ")\n",
    "row_group_size_per_file = {}\n",
    "sum_row_group_size = 0\n",
    "num_row_groups = 0\n",
    "for file, row_group_metadata in row_group_metadata_per_file.items():\n",
    "    print(f\"{file}\")\n",
    "    row_group_size_per_file[file] = {}\n",
    "    for row_group, metadata in row_group_metadata.items():\n",
    "        row_group_size_per_file[file][row_group] = metadata[\"total_byte_size\"] / (\n",
    "            1024 * 1024\n",
    "        )\n",
    "        sum_row_group_size += row_group_size_per_file[file][row_group]\n",
    "        num_row_groups += 1\n",
    "        print(f\"     {row_group}: {row_group_size_per_file[file][row_group]} MB\")\n",
    "\n",
    "print(f\"Average row group size: {sum_row_group_size/num_row_groups} MB\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we see that the row groups are about 200MB and the file sizes are a 1GB. This is a little smaller because the less files the more common metadata is stored together. I would try to store all the data in the same file in this case"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: normalize_dataset\n",
      "Done with task: normalize_dataset\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "============================================================\n",
      "PARQUETDB SUMMARY\n",
      "============================================================\n",
      "Database path: Z:\\data\\parquetdb\\data\\external\\alexandria\\AlexandriaDB\\alexandria_3D\n",
      "\n",
      "• Number of columns: 128\n",
      "• Number of rows: 4389295\n",
      "• Number of files: 1\n",
      "• Number of rows per file: [4389295]\n",
      "• Number of row groups per file: [22]\n",
      "• Number of rows per row group per file: \n",
      "    - alexandria_3D_0.parquet:\n",
      "        - Row group 0: 200000 rows\n",
      "        - Row group 1: 200000 rows\n",
      "        - Row group 2: 200000 rows\n",
      "        - Row group 3: 200000 rows\n",
      "        - Row group 4: 200000 rows\n",
      "        - Row group 5: 200000 rows\n",
      "        - Row group 6: 200000 rows\n",
      "        - Row group 7: 200000 rows\n",
      "        - Row group 8: 200000 rows\n",
      "        - Row group 9: 200000 rows\n",
      "        - Row group 10: 200000 rows\n",
      "        - Row group 11: 200000 rows\n",
      "        - Row group 12: 200000 rows\n",
      "        - Row group 13: 200000 rows\n",
      "        - Row group 14: 200000 rows\n",
      "        - Row group 15: 200000 rows\n",
      "        - Row group 16: 200000 rows\n",
      "        - Row group 17: 200000 rows\n",
      "        - Row group 18: 200000 rows\n",
      "        - Row group 19: 200000 rows\n",
      "        - Row group 20: 200000 rows\n",
      "        - Row group 21: 189295 rows\n",
      "• Serialized metadata size per file: [377883] Bytes\n",
      "\n",
      "############################################################\n",
      "METADATA\n",
      "############################################################\n",
      "\n",
      "############################################################\n",
      "COLUMN DETAILS\n",
      "############################################################\n",
      "\n",
      "alexandria_3D_0.parquet: 2767.1490955352783 MB\n"
     ]
    }
   ],
   "source": [
    "normalize_config = NormalizeConfig(\n",
    "    load_format=\"batches\",  # Uses the batch generator to normalize\n",
    "    batch_readahead=4,  # Controls the number of batches to load in memory a head of time. This will have impacts on amount of RAM consumed\n",
    "    fragment_readahead=1,  # Controls the number of files to load in memory ahead of time. This will have impacts on amount of RAM consumed\n",
    "    batch_size=10000,  # Controls the batchsize when to use when normalizing. This will have impacts on amount of RAM consumed\n",
    "    max_rows_per_file=5000000,  # Controls the max number of rows per parquet file\n",
    "    max_rows_per_group=200000,\n",
    "    min_rows_per_group=200000,\n",
    ")  # Controls the max number of rows per group parquet file\n",
    "normalize_dataset(db, normalize_config=normalize_config)\n",
    "print(db.summary(show_row_group_metadata=True))\n",
    "\n",
    "file_sizes = list_file_sizes(db.db_path)\n",
    "for file, size in file_sizes.items():\n",
    "    print(f\"{file}: {size} MB\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Operations\n",
    "\n",
    "In this section we are going to test the performance of ParquetDB for basic operations.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reading a single column\n",
    "\n",
    "\n",
    "If one were to want a single property for all materials in alexandria, if it were in json format, we would have to iterate  over and read all the json files to collect the property. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_single_column\n",
      "(4389295, 1)\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 0.06 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "total_time_to_read_from_json = sum(benchmark_dict[\"json_load_times\"])\n",
    "\n",
    "\n",
    "def read_single_column(db):\n",
    "    task_name = \"read_single_column\"\n",
    "    print(\"Starting task: read_single_column\")\n",
    "    table = db.read(columns=[\"id\"], load_format=\"table\")\n",
    "    print(table.shape)\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_single_column(db)\n",
    "read_single_column_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_single_column_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_single_column_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reading specific ids\n",
    "\n",
    "Now, if we were to want speific columns, at minimum time to do this in json format would be the same time as iterating over the json files.\n",
    "\n",
    "In ParquetDB, it is much simpler and less memory intensive to read specific ids.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_specific_ids\n",
      "0      10000\n",
      "1          0\n",
      "2         10\n",
      "3        100\n",
      "4       1000\n",
      "5     100000\n",
      "6    1000000\n",
      "Name: id, dtype: int64\n",
      "                   @class                            @module  composition.Ac  \\\n",
      "0  ComputedStructureEntry  pymatgen.entries.computed_entries             2.0   \n",
      "1  ComputedStructureEntry  pymatgen.entries.computed_entries             1.0   \n",
      "2  ComputedStructureEntry  pymatgen.entries.computed_entries             1.0   \n",
      "3  ComputedStructureEntry  pymatgen.entries.computed_entries             1.0   \n",
      "4  ComputedStructureEntry  pymatgen.entries.computed_entries             2.0   \n",
      "\n",
      "   composition.Ag  composition.Al  composition.Ar  composition.As  \\\n",
      "0             NaN             NaN             NaN             NaN   \n",
      "1             NaN             NaN             NaN             NaN   \n",
      "2             NaN             NaN             NaN             NaN   \n",
      "3             NaN             NaN             NaN             NaN   \n",
      "4             NaN             NaN             NaN             NaN   \n",
      "\n",
      "   composition.Au  composition.B  composition.Ba  ...  structure.lattice.a  \\\n",
      "0             NaN            NaN             NaN  ...             4.829086   \n",
      "1             NaN            NaN             NaN  ...            10.091510   \n",
      "2             NaN            NaN             NaN  ...            15.519920   \n",
      "3             NaN            NaN             NaN  ...             5.789011   \n",
      "4             NaN            NaN             NaN  ...             8.695520   \n",
      "\n",
      "   structure.lattice.alpha  structure.lattice.b  structure.lattice.beta  \\\n",
      "0                90.000000             4.829086               90.000000   \n",
      "1               109.471217            10.091510              109.471222   \n",
      "2                89.997963            11.000739               89.996986   \n",
      "3               111.411199             8.109282               99.469696   \n",
      "4                69.601810             7.709933               55.506047   \n",
      "\n",
      "   structure.lattice.c  structure.lattice.gamma  \\\n",
      "0             9.745281                90.000000   \n",
      "1            10.091511               109.471219   \n",
      "2             5.192681                45.191179   \n",
      "3             8.109282                99.469696   \n",
      "4             7.709933                55.506037   \n",
      "\n",
      "                            structure.lattice.matrix  structure.lattice.pbc  \\\n",
      "0  [4.82908586, 0.0, 0.0, 0.0, 4.82908586, 0.0, 0...     [True, True, True]   \n",
      "1  [9.51436671, 2e-08, -3.36383678, -4.75718337, ...     [True, True, True]   \n",
      "2  [15.51989271, -0.00721914, 0.02799947, 7.75631...     [True, True, True]   \n",
      "3  [5.78373142, -0.13705652, -0.20571227, -1.1463...     [True, True, True]   \n",
      "4  [7.92465233, 0.98010515, 3.44257929, 3.2101699...     [True, True, True]   \n",
      "\n",
      "   structure.lattice.volume                                    structure.sites  \n",
      "0                227.260645  [{'abc': [0.0, 0.5, 0.2399718], 'label': 'Ac',...  \n",
      "1                791.127799  [{'abc': [0.0, 0.0, 0.0], 'label': 'Ac', 'prop...  \n",
      "2                628.973408  [{'abc': [3e-06, 3e-06, 0.0], 'label': 'Ac', '...  \n",
      "3                338.968680  [{'abc': [0.5, 0.0, 0.0], 'label': 'Ac', 'prop...  \n",
      "4                350.818535  [{'abc': [0.83221258, 0.94982224, 0.94982224],...  \n",
      "\n",
      "[5 rows x 128 columns]\n",
      "(7, 128)\n",
      "[dtype('O'), dtype('int64'), dtype('float64')]\n",
      "Data : 129\n",
      "['@class', '@module', 'composition.Ac', 'composition.Ag', 'composition.Al', 'composition.Ar', 'composition.As', 'composition.Au', 'composition.B', 'composition.Ba', 'composition.Be', 'composition.Bi', 'composition.Br', 'composition.C', 'composition.Ca', 'composition.Cd', 'composition.Ce', 'composition.Cl', 'composition.Co', 'composition.Cr', 'composition.Cs', 'composition.Cu', 'composition.Dy', 'composition.Er', 'composition.Eu', 'composition.F', 'composition.Fe', 'composition.Ga', 'composition.Gd', 'composition.Ge', 'composition.H', 'composition.He', 'composition.Hf', 'composition.Hg', 'composition.Ho', 'composition.I', 'composition.In', 'composition.Ir', 'composition.K', 'composition.Kr', 'composition.La', 'composition.Li', 'composition.Lu', 'composition.Mg', 'composition.Mn', 'composition.Mo', 'composition.N', 'composition.Na', 'composition.Nb', 'composition.Nd', 'composition.Ne', 'composition.Ni', 'composition.Np', 'composition.O', 'composition.Os', 'composition.P', 'composition.Pa', 'composition.Pb', 'composition.Pd', 'composition.Pm', 'composition.Pr', 'composition.Pt', 'composition.Pu', 'composition.Rb', 'composition.Re', 'composition.Rh', 'composition.Ru', 'composition.S', 'composition.Sb', 'composition.Sc', 'composition.Se', 'composition.Si', 'composition.Sm', 'composition.Sn', 'composition.Sr', 'composition.Ta', 'composition.Tb', 'composition.Tc', 'composition.Te', 'composition.Th', 'composition.Ti', 'composition.Tl', 'composition.Tm', 'composition.U', 'composition.V', 'composition.W', 'composition.Xe', 'composition.Y', 'composition.Yb', 'composition.Zn', 'composition.Zr', 'correction', 'data.band_gap_dir', 'data.band_gap_ind', 'data.decomposition', 'data.dos_ef', 'data.e_above_hull', 'data.e_form', 'data.e_phase_separation', 'data.elements', 'data.energy_corrected', 'data.energy_total', 'data.formula', 'data.location', 'data.mat_id', 'data.nsites', 'data.prototype_id', 'data.spg', 'data.stress', 'data.total_mag', 'energy', 'energy_adjustments', 'entry_id', 'id', 'parameters.dummy_field', 'structure.@class', 'structure.@module', 'structure.charge', 'structure.lattice.a', 'structure.lattice.alpha', 'structure.lattice.b', 'structure.lattice.beta', 'structure.lattice.c', 'structure.lattice.gamma', 'structure.lattice.matrix', 'structure.lattice.pbc', 'structure.lattice.volume', 'structure.sites']\n",
      "Done with task: read_specific_ids\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 4.36 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_specific_ids(db):\n",
    "    task_name = \"read_specific_ids\"\n",
    "    print(\"Starting task: read_specific_ids\")\n",
    "    table = db.read(\n",
    "        ids=[\n",
    "            0,\n",
    "            10,\n",
    "            100,\n",
    "            1000,\n",
    "            10000,\n",
    "            100000,\n",
    "            1000000,\n",
    "        ],  # Controls which rows we want to read\n",
    "        load_format=\"table\",  # Controls the output format. The options are 'table', 'batches', `dataset`.\n",
    "    )\n",
    "\n",
    "    df = table.to_pandas()  # Converts the table to a pandas dataframe\n",
    "    print(df[\"id\"])\n",
    "    print(df.head())\n",
    "    print(df.shape)\n",
    "\n",
    "    print(f\"Data : {df.iloc[0]['data.spg']}\")\n",
    "    print(list(df.columns))\n",
    "    print(\"Done with task: read_specific_ids\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_specific_ids(db)\n",
    "read_specific_ids_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_specific_ids_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_specific_ids_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Finding the minimum and maximum of a energy\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_energy_min_max\n",
      "(4389295, 1)\n",
      "Min: -1496.5922219, Max: -0.003981\n",
      "Done with task: read_energy_min_max\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 0.11 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_energy_min_max(db):\n",
    "    task_name = \"read_energy_min_max\"\n",
    "    print(\"Starting task: read_energy_min_max\")\n",
    "    table = db.read(columns=[\"energy\"], load_format=\"table\")\n",
    "    print(table.shape)\n",
    "\n",
    "    result = pc.min_max(table[\"energy\"])\n",
    "    # The result will be a struct with 'min' and 'max' fields\n",
    "    min_value = result[\"min\"].as_py()\n",
    "    max_value = result[\"max\"].as_py()\n",
    "\n",
    "    print(f\"Min: {min_value}, Max: {max_value}\")\n",
    "    print(\"Done with task: read_energy_min_max\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_energy_min_max(db)\n",
    "read_energy_min_max_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_energy_min_max_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_energy_min_max_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reading records filtered by energy above -1.0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_filtered_energy_above_minus_one\n",
      "       id    energy\n",
      "0  123136 -0.063105\n",
      "1  123137 -0.125970\n",
      "2  403318 -0.972671\n",
      "3  570682 -0.907343\n",
      "4  570683 -0.901483\n",
      "(46, 2)\n",
      "Done with task: read_filtered_energy_above_minus_one\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 0.04 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_filtered_energy_above_minus_one(db):\n",
    "    task_name = \"read_filtered_energy_above_-1\"\n",
    "\n",
    "    \"\"\"Read records filtered by energy above -1.0 and track timing.\"\"\"\n",
    "    print(\"Starting task: read_filtered_energy_above_minus_one\")\n",
    "\n",
    "    table = db.read(\n",
    "        columns=[\"id\", \"energy\"],\n",
    "        filters=[pc.field(\"energy\") > -1.0],\n",
    "        load_format=\"table\",\n",
    "    )\n",
    "\n",
    "    df = table.to_pandas()  # Converts the table to a pandas dataframe\n",
    "    print(df.head())\n",
    "    print(df.shape)\n",
    "    print(\"Done with task: read_filtered_energy_above_minus_one\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_filtered_energy_above_minus_one(db)\n",
    "read_filtered_energy_above_minus_one_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_filtered_energy_above_minus_one_time)\n",
    "\n",
    "print(\n",
    "    f\"Time to read from parquetdb: {read_filtered_energy_above_minus_one_time:.2f} seconds\"\n",
    ")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reading records filtered by spg 204\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_filtered_spg_204\n",
      "      id  data.spg\n",
      "0  10113       204\n",
      "1  10125       204\n",
      "2  10126       204\n",
      "3  10133       204\n",
      "4  10140       204\n",
      "(7240, 2)\n",
      "Done with task: read_filtered_spg_204\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 0.05 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_filtered_spg_204(db):\n",
    "    task_name = \"read_filtered_spg_204_table\"\n",
    "\n",
    "    print(\"Starting task: read_filtered_spg_204\")\n",
    "    table = db.read(\n",
    "        columns=[\"id\", \"data.spg\"],\n",
    "        filters=[pc.field(\"data.spg\") == 204],\n",
    "        load_format=\"table\",\n",
    "    )\n",
    "\n",
    "    df = table.to_pandas()  # Converts the table to a pandas dataframe\n",
    "    print(df.head())\n",
    "    print(df.shape)\n",
    "\n",
    "    print(\"Done with task: read_filtered_spg_204\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_filtered_spg_204(db)\n",
    "read_filtered_spg_204_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_filtered_spg_204_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_filtered_spg_204_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reading records filtered by spg batches\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_filtered_spg_batches\n",
      "Total number of rows: 7240, Batches: 4390\n",
      "Done with task: read_filtered_spg_batches\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 0.87 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_filtered_spg_batches(db):\n",
    "    task_name = \"read_filtered_spg_batches\"\n",
    "    print(\"Starting task: read_filtered_spg_batches\")\n",
    "    generator = db.read(\n",
    "        load_format=\"batches\",\n",
    "        batch_size=1000,\n",
    "        load_config=LoadConfig(\n",
    "            batch_readahead=10,\n",
    "            fragment_readahead=2,\n",
    "            fragment_scan_options=None,\n",
    "            use_threads=True,\n",
    "            memory_pool=None,\n",
    "        ),\n",
    "        columns=[\"id\", \"data.spg\"],\n",
    "        filters=[pc.field(\"data.spg\") == 204],\n",
    "    )\n",
    "\n",
    "    batch_count = 0\n",
    "    num_rows = 0\n",
    "    for table in generator:\n",
    "        df = table.to_pandas()\n",
    "        num_rows += table.num_rows\n",
    "        batch_count += 1\n",
    "    print(f\"Total number of rows: {num_rows}, Batches: {batch_count}\")\n",
    "    print(\"Done with task: read_filtered_spg_batches\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_filtered_spg_batches(db)\n",
    "read_filtered_spg_batches_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_filtered_spg_batches_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_filtered_spg_batches_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reading lattice matrix for space group 204\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_lattice_matrix_spg_204\n",
      "(7240, 3, 3)\n",
      "Done with task: read_lattice_matrix_spg_204\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 0.22 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_lattice_matrix_spg_204(db):\n",
    "    task_name = \"read_lattice_matrix_spg_204\"\n",
    "\n",
    "    print(\"Starting task: read_lattice_matrix_spg_204\")\n",
    "\n",
    "    table = db.read(\n",
    "        columns=[\"structure.lattice.matrix\"], filters=[pc.field(\"data.spg\") == 204]\n",
    "    )\n",
    "    lattice = table[\"structure.lattice.matrix\"].combine_chunks().to_numpy_ndarray()\n",
    "    print(lattice.shape)\n",
    "    print(\"Done with task: read_lattice_matrix_spg_204\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_lattice_matrix_spg_204(db)\n",
    "read_lattice_matrix_spg_204_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_lattice_matrix_spg_204_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_lattice_matrix_spg_204_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reading nested column selection\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_nested_column_selection\n",
      "(4389295, 2)\n",
      "list<element: struct<abc: list<element: double>, label: string, properties: struct<charge: double, forces: list<element: double>, magmom: double>, species: list<element: struct<element: string, occu: int64>>, xyz: list<element: double>>>\n",
      "list<element: struct<abc: list<element: double>, label: string, properties: struct<charge: double, forces: list<element: double>, magmom: double>, species: list<element: struct<element: string, occu: int64>>, xyz: list<element: double>>>\n",
      "Done with task: read_nested_column_selection\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 4.58 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_nested_column_selection(db):\n",
    "    task_name = \"read_nested_column_selection\"\n",
    "\n",
    "    print(\"Starting task: read_nested_column_selection\")\n",
    "    table = db.read(columns=[\"id\", \"structure.sites\"], load_format=\"table\")\n",
    "\n",
    "    print(table.shape)\n",
    "    print(table[\"structure.sites\"].type)\n",
    "    print(table[\"structure.sites\"].combine_chunks().type)\n",
    "    print(\"Done with task: read_nested_column_selection\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "task_name = read_nested_column_selection(db)\n",
    "read_nested_column_selection_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(read_nested_column_selection_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {read_nested_column_selection_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Nested structure into class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_nested_structure_into_class\n",
      "(2, 3)\n",
      "struct<band_gap_dir: double, band_gap_ind: double, decomposition: string, dos_ef: double, e_above_hull: double, e_form: double, e_phase_separation: double, elements: list<element: string>, energy_corrected: double, energy_total: double, formula: string, location: string, mat_id: string, nsites: int64, prototype_id: string, spg: int64, stress: extension<arrow.fixed_shape_tensor[value_type=double, shape=[3,3]]>, total_mag: double>\n",
      "structure type\n",
      "struct<@class: string, @module: string, charge: int64, lattice: struct<a: double, alpha: double, b: double, beta: double, c: double, gamma: double, matrix: extension<arrow.fixed_shape_tensor[value_type=double, shape=[3,3]]>, pbc: extension<arrow.fixed_shape_tensor[value_type=bool, shape=[3]]>, volume: double>, sites: list<element: struct<abc: list<element: double>, label: string, properties: struct<charge: double, forces: list<element: double>, magmom: double>, species: list<element: struct<element: string, occu: int64>>, xyz: list<element: double>>>>\n",
      "Full Formula (Ac1 Pr12 Ho7)\n",
      "Reduced Formula: AcPr12Ho7\n",
      "abc   :  10.091510  10.091510  10.091511\n",
      "angles: 109.471217 109.471222 109.471219\n",
      "pbc   :       True       True       True\n",
      "Sites (20)\n",
      "  #  SP           a         b         c    charge  forces                                     magmom\n",
      "---  ----  --------  --------  --------  --------  ---------------------------------------  --------\n",
      "  0  Ac    0         0         0            8.076  [0.0, -0.0, -0.0]                              -0\n",
      "  1  Pr    0.476206  0.707375  0.768831     8.873  [0.0022184, 0.00231648, -0.00126846]           -0\n",
      "  2  Pr    0.938545  0.707375  0.231169     8.873  [0.00045645, 0.00231648, -0.00251434]          -0\n",
      "  3  Pr    0.523794  0.292625  0.231169     8.873  [-0.0022184, -0.00231648, 0.00126846]          -0\n",
      "  4  Pr    0.061455  0.292625  0.768831     8.873  [-0.00045645, -0.00231648, 0.00251434]         -0\n",
      "  5  Pr    0.768831  0.061455  0.292625     8.873  [0.00177791, -0.00155354, -0.00251434]         -0\n",
      "  6  Pr    0.768831  0.476206  0.707375     8.873  [-0.00089694, 0.00307943, 0.00126846]          -0\n",
      "  7  Pr    0.231169  0.938545  0.707375     8.873  [-0.00177791, 0.00155354, 0.00251434]          -0\n",
      "  8  Pr    0.231169  0.523794  0.292625     8.873  [0.00089694, -0.00307943, -0.00126846]         -0\n",
      "  9  Pr    0.707375  0.768831  0.476206     8.873  [0.00223436, 0.00076295, 0.00251434]           -0\n",
      " 10  Pr    0.292625  0.231169  0.523794     8.873  [-0.00223436, -0.00076295, -0.00251434]        -0\n",
      " 11  Pr    0.707375  0.231169  0.938545     8.873  [0.00311533, -0.00076295, 0.00126846]          -0\n",
      " 12  Pr    0.292625  0.768831  0.061455     8.873  [-0.00311533, 0.00076295, -0.00126846]         -0\n",
      " 13  Ho    0.5       0.5       0            7.546  [-0.0, -0.0, -0.0]                              0\n",
      " 14  Ho    0         0.5       0.5          7.546  [0.0, -0.0, -0.0]                               0\n",
      " 15  Ho    0.5       0         0.5          7.546  [-0.0, -0.0, -0.0]                              0\n",
      " 16  Ho    0.5       0.5       0.5          8.703  [-0.0, -0.0, -0.0]                              0\n",
      " 17  Ho    0         0         0.5          8.703  [-0.0, -0.0, -0.0]                              0\n",
      " 18  Ho    0.5       0         0            8.703  [-0.0, -0.0, -0.0]                              0\n",
      " 19  Ho    0         0.5       0            8.703  [-0.0, -0.0, -0.0]                              0\n",
      "Done with task: read_nested_structure_into_class\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 52.64 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "def read_nested_structure_into_class(db):\n",
    "    # By default the database flattens nested structure for storage.\n",
    "    # However, we provide an option to rebuild the nested structure. This will create a new dataset in {dataset_name}_nested.\n",
    "    # After the creation of the new dataset, the query parameters are applied to the new dataset.\n",
    "    task_name = \"read_nested_structure_into_class\"\n",
    "\n",
    "    print(\"Starting task: read_nested_structure_into_class\")\n",
    "    table = db.read(\n",
    "        columns=[\n",
    "            \"id\",\n",
    "            \"structure\",\n",
    "            \"data\",\n",
    "        ],  # Instead of using the flatten syntax, we can use the nested syntax\n",
    "        ids=[0, 1000000],\n",
    "        load_format=\"table\",\n",
    "        rebuild_nested_struct=True,  # When set to True to rebuild the nested structure\n",
    "        rebuild_nested_from_scratch=False,  # When set to True, the nested structure will be rebuilt from scratch\n",
    "        normalize_config=NormalizeConfig(\n",
    "            load_format=\"batches\",\n",
    "            batch_readahead=2,\n",
    "            fragment_readahead=1,\n",
    "            batch_size=10000,\n",
    "            max_rows_per_file=5000000,\n",
    "            min_rows_per_group=200000,\n",
    "            max_rows_per_group=200000,\n",
    "        ),\n",
    "    )\n",
    "\n",
    "    print(table.shape)\n",
    "    print(table[\"data\"].type)\n",
    "\n",
    "    print(\"structure type\")\n",
    "    print(table[\"structure\"].type)\n",
    "    try:\n",
    "        from pymatgen.core.structure import Structure\n",
    "\n",
    "        structure = Structure.from_dict(\n",
    "            table[\"structure\"].combine_chunks().to_pylist()[0]\n",
    "        )\n",
    "\n",
    "        print(structure)\n",
    "    except Exception as e:\n",
    "        print(e)\n",
    "    print(\"Done with task: read_nested_structure_into_class\")\n",
    "    print(\"-\" * 200)\n",
    "    return task_name\n",
    "\n",
    "\n",
    "start_time = time.time()\n",
    "read_nested_structure_into_class(db)\n",
    "nested_structure_time = time.time() - start_time\n",
    "\n",
    "print(f\"Time to read from parquetdb: {nested_structure_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the previous cell it takes ~ 60 seconds to perform the operation, this is due to reconstructing the nested structure. Further queries will be faster as the nested structure is already built.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting task: read_nested_structure_into_class\n",
      "(2, 3)\n",
      "struct<band_gap_dir: double, band_gap_ind: double, decomposition: string, dos_ef: double, e_above_hull: double, e_form: double, e_phase_separation: double, elements: list<element: string>, energy_corrected: double, energy_total: double, formula: string, location: string, mat_id: string, nsites: int64, prototype_id: string, spg: int64, stress: extension<arrow.fixed_shape_tensor[value_type=double, shape=[3,3]]>, total_mag: double>\n",
      "structure type\n",
      "struct<@class: string, @module: string, charge: int64, lattice: struct<a: double, alpha: double, b: double, beta: double, c: double, gamma: double, matrix: extension<arrow.fixed_shape_tensor[value_type=double, shape=[3,3]]>, pbc: extension<arrow.fixed_shape_tensor[value_type=bool, shape=[3]]>, volume: double>, sites: list<element: struct<abc: list<element: double>, label: string, properties: struct<charge: double, forces: list<element: double>, magmom: double>, species: list<element: struct<element: string, occu: int64>>, xyz: list<element: double>>>>\n",
      "Full Formula (Ac1 Pr12 Ho7)\n",
      "Reduced Formula: AcPr12Ho7\n",
      "abc   :  10.091510  10.091510  10.091511\n",
      "angles: 109.471217 109.471222 109.471219\n",
      "pbc   :       True       True       True\n",
      "Sites (20)\n",
      "  #  SP           a         b         c    charge  forces                                     magmom\n",
      "---  ----  --------  --------  --------  --------  ---------------------------------------  --------\n",
      "  0  Ac    0         0         0            8.076  [0.0, -0.0, -0.0]                              -0\n",
      "  1  Pr    0.476206  0.707375  0.768831     8.873  [0.0022184, 0.00231648, -0.00126846]           -0\n",
      "  2  Pr    0.938545  0.707375  0.231169     8.873  [0.00045645, 0.00231648, -0.00251434]          -0\n",
      "  3  Pr    0.523794  0.292625  0.231169     8.873  [-0.0022184, -0.00231648, 0.00126846]          -0\n",
      "  4  Pr    0.061455  0.292625  0.768831     8.873  [-0.00045645, -0.00231648, 0.00251434]         -0\n",
      "  5  Pr    0.768831  0.061455  0.292625     8.873  [0.00177791, -0.00155354, -0.00251434]         -0\n",
      "  6  Pr    0.768831  0.476206  0.707375     8.873  [-0.00089694, 0.00307943, 0.00126846]          -0\n",
      "  7  Pr    0.231169  0.938545  0.707375     8.873  [-0.00177791, 0.00155354, 0.00251434]          -0\n",
      "  8  Pr    0.231169  0.523794  0.292625     8.873  [0.00089694, -0.00307943, -0.00126846]         -0\n",
      "  9  Pr    0.707375  0.768831  0.476206     8.873  [0.00223436, 0.00076295, 0.00251434]           -0\n",
      " 10  Pr    0.292625  0.231169  0.523794     8.873  [-0.00223436, -0.00076295, -0.00251434]        -0\n",
      " 11  Pr    0.707375  0.231169  0.938545     8.873  [0.00311533, -0.00076295, 0.00126846]          -0\n",
      " 12  Pr    0.292625  0.768831  0.061455     8.873  [-0.00311533, 0.00076295, -0.00126846]         -0\n",
      " 13  Ho    0.5       0.5       0            7.546  [-0.0, -0.0, -0.0]                              0\n",
      " 14  Ho    0         0.5       0.5          7.546  [0.0, -0.0, -0.0]                               0\n",
      " 15  Ho    0.5       0         0.5          7.546  [-0.0, -0.0, -0.0]                              0\n",
      " 16  Ho    0.5       0.5       0.5          8.703  [-0.0, -0.0, -0.0]                              0\n",
      " 17  Ho    0         0         0.5          8.703  [-0.0, -0.0, -0.0]                              0\n",
      " 18  Ho    0.5       0         0            8.703  [-0.0, -0.0, -0.0]                              0\n",
      " 19  Ho    0         0.5       0            8.703  [-0.0, -0.0, -0.0]                              0\n",
      "Done with task: read_nested_structure_into_class\n",
      "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
      "Time to read from parquetdb: 3.75 seconds\n",
      "Time to read from json: 589.19 seconds\n"
     ]
    }
   ],
   "source": [
    "start_time = time.time()\n",
    "task_name = read_nested_structure_into_class(db)\n",
    "nested_structure_time = time.time() - start_time\n",
    "\n",
    "task_benchmark_dict[\"task_names\"].append(task_name)\n",
    "task_benchmark_dict[\"task_times\"].append(nested_structure_time)\n",
    "\n",
    "print(f\"Time to read from parquetdb: {nested_structure_time:.2f} seconds\")\n",
    "print(f\"Time to read from json: {total_time_to_read_from_json:.2f} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Plotting times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from parquetdb.utils import matplotlib_utils\n",
    "from matplotlib import rcParams\n",
    "from mpl_toolkits.axes_grid1.inset_locator import inset_axes\n",
    "\n",
    "%matplotlib inline\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\lllang\\AppData\\Local\\Temp\\ipykernel_35236\\2220293953.py:54: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\n",
      "  plt.tight_layout()\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABA4AAAJOCAYAAAA3VkUWAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1QU19sH8O/SOyKiqCjgqoBdsSKICmIniorYAEsUu4m9AjaiScTExJLEXqKiwRYbKiL2JGo0VixYsIuggqKw9/2Dd+fHursIiGL5fs7hHJ25c+eZsrszz9y5VyaEECAiIiIiIiIi0kCnqAMgIiIiIiIiog8XEwdEREREREREpBUTB0RERERERESkFRMHRERERERERKQVEwdEREREREREpBUTB0RERERERESkFRMHRERERERERKQVEwdEREREREREpBUTB0RERERERESkFRMHRPTBkclk+f5r2rRpUYctcXBwgEwmQ2Ji4hvLBgcHF2h7ExMTsWzZMshkMgQHB7/zbXqXDh8+DB8fHxQvXhw6OjqQyWRYtmxZkcQSGBgImUyGgICAPJWPjIyETCZDlSpV3mlcYWFhkMlkCAsLe6frKSo7d+5Ejx494OjoCBMTE1hYWKBKlSoYMmQIzp49W9ThfTDy891ChWv//v0f3G8NAU2bNoVMJsP+/fvzvez7+jz9+++/MDAwgEwmQ8WKFQtUhxACq1evhre3N0qUKAF9fX0UK1YMjRs3xo8//oiXL18WctQFo+23KrfPj/K65nVvc2zp3dAr6gCIiF4XFBSkNu3u3bvYtWuX1vnOzs75Wsf+/fvRrFkzeHp6FumPkru7u8bpGzZsQFpaGho3bqzxQsPMzOxdh/Ze3L59G23btkVqairc3d3h4OAAHR2dAl9cva2+ffti5cqV2LRpEx4/fgwrK6tcyy9dulRajvLvyZMn6N69O/78808AQNWqVdGuXTu8evUKf//9N37++WcsWLAA48aNw/Tp0zVeXH4qgoODsXz5cixduvSjTwbSm4WFhSE8PByhoaEfZULQwcEB169fx7Vr1+Dg4FDU4aj5UPbvy5cvERgYiMzMzLeqp1u3bli3bh10dHTg5uaGsmXL4t69ezh06BAOHz6M33//Hfv27YOxsXEhRU6kjokDIvrgaHravH//filxUFRPo9+Ffv36oV+/fmrT9+/fj7S0NPTr10/rTUTHjh3RsGFDWFpavuMo353du3cjJSUF3bt3x+rVq4s6HDRp0gQVK1bE5cuXsXr1agwZMkRr2b/++gtnzpyBvr4+evXq9U7jGjJkCAICAlCiRIl3up736eXLl/Dx8cGxY8fg6OiIlStXonHjxtJ8IQRWrVqFkJAQzJw5E8+fP8ecOXOKMOKit3fvXrx69Qply5Yt6lCIPggrVqxAeno6ypcvX9ShaDR16lScPn0aQ4YMwU8//VSgOqKjo7Fu3TpYWloiLi4ONWvWlOZdvXoVTZo0wdGjR/HDDz9g3LhxhRV6gRTmb9WHfmw/R3xVgYjoI2VpaQlnZ2eULl26qEMpsBs3bgAAKlWqVMSRZJPJZOjTpw+A/7Um0EY5v127dihZsuQ7jatEiRJwdnb+pBIH4eHhOHbsGIoVK4bY2FiVpAGQfSx69eqFdevWAch+LWTPnj1FEeoHQy6Xw9nZGfr6+kUdCtEHoXz58nB2doaJiUlRh6Lmr7/+wjfffIMuXbqgU6dOBa5n3759AIAePXqoJA0AoEKFChg0aBAA4MiRIwUPtpAU5m/Vh3xsP1dMHBDRJ+HWrVsYOnQoKlWqBCMjI1haWqJx48ZYtGgRsrKyVMo2bdoUzZo1AwDExcWp9B2Qs8nlgwcP8OOPP6JNmzZwdHSEsbExLCwsULduXcyaNQsvXrx4n5uoRlsfBznfJczIyEB4eDgqV64MIyMjlC9fHmPHjpViT01NxahRo1ChQgUYGRnBwcEBYWFhuTar3Lt3L/z8/FC6dGkYGBigZMmS6NixY74uWpSxh4aGAsi+idR0DID8HdvX90tycjJGjBgBuVwOQ0PDPL2fHBwcDF1dXZw4cQKnT5/WWObFixf4/fffAfzvNYWnT5/i119/hZ+fHypVqgRTU1OYmpqievXqmDhxIlJSUjTWlfM9282bN6N58+YoXry4yrudb+rjYNeuXVICw8DAAGXKlEHXrl3x999/v3Gd2vaBpr4mMjIy8O2338LV1RXm5uYwMDCAra0t6tWrhzFjxiA5OVljfa97+vSp9PRt8uTJsLe311q2Xbt28PX1BQDMmDFDZV7OY/3o0SMMHjwY5cuXh6GhIezt7fHVV1/h8ePHWuu+ffs2vv76a7i4uMDExATm5uaoV68efvrpJ42fgZz75b///kPXrl1RunRp6OrqSsfm1atXWLVqFXr06AFnZ2dYWFjA2NgYTk5OGDZsGG7fvq1SZ2JiImQyGZYvXw4A6N27t8p3Us5jnttxS09PxzfffIM6derA3NwcJiYmqFq1KiZNmqRxHyjX6+DgACEEfvnlF7i6usLU1BSWlpbw8fHR+plOSEhAnz594OjoCENDQ5iZmcHe3h5t27Z9Y8JNk+PHj8Pf3x9lypSRvlPat2+PmJgYjeVzHodr166hV69esLW1haGhIeRyOSZNmoSMjIx8xwFkP+WsV68eTExMULx4cbRq1Qrx8fG5LvPHH3+gX79+qFatGqysrGBkZARHR0f06dMHFy9eVCsvk8kQHh4OQPW77/Xv83PnziE0NBSNGzdG2bJlYWBgAGtra3h7e2P9+vVa49mzZw/at2+PUqVKQV9fH1ZWVqhUqRJ69uyJAwcOaFwmr9/rys/c9evXAQCOjo4q8b/p1b+UlBTo6urCysoKCoVCZd769eulerZv364yLyMjAyYmJjAyMsLz58+l6Zreg8/r/s0pNjYWPj4+sLKygrGxMerUqYMVK1bkui25efHiBYKCgmBlZVXglgZKRkZGeSqXn5v1d3WdUJj98eTWx0FmZiYWLlwINzc3WFpawsjICJUqVcKwYcOQlJSksb6cfSls3LgR7u7usLCwgKmpKRo3bqx2zuU3xvj4eLRv3x42NjbQ0dFR+f3Mz3XMli1bIJPJpN+9nAYNGgSZTAZ9fX08efJEZd6BAwcgk8nQpEkTlen//PMPunbtCjs7OxgYGMDCwgIVKlRAp06dsHnz5vxtsCAi+gjExsYKAELT19bx48dF8eLFBQBRvnx50bVrV9GqVSthZGQkAIiWLVuKjIwMqXxERIRo2bKlACBKlSolgoKCpL+RI0dK5VauXCkAiLJlywpPT08REBAgvLy8hJmZmQAgGjVqJF68eKEWj729vQAgrl27VuDtVdaxdOlSrWWWLl0qAIigoCCV6cp91ahRI+Hp6SksLCyEr6+vaNeunbC0tBQARLt27cSjR4+Ek5OTsLGxEZ06dRI+Pj7SPgsJCdG4zpEjRwoAQkdHR9SvX1906dJFNGjQQMhkMqGrqyuWLFmSp+2Lj48XQUFBombNmgKAqFmzpsZjkN9jm3O/tG3bVjg6OgorKyvh6+srunTpInr06JGn+Nq3by8AiGHDhmmcv3r1agFAlClTRmRmZkrbBEDY2NgId3d30bVrV+Hj4yOsra0FAFGxYkXx8OFDtbqUx3rIkCECgKhbt67o1q2b8PT0FAcOHBBCCBEaGioAiNDQULXlJ02aJAAImUwmGjduLLp16yZq1aolAAhdXV2xePFirevUdo4GBQWpnX9ZWVnCy8tLABAWFhaidevWolu3bsLb21uq7+TJk7nv2P+3adMm6fN8//79N5bfsGGDdN6lpKRI05XH2tfXV8jlclGsWDHRoUMH0bFjR2FlZSUACCcnJ43riIuLk8o4ODgIX19f0bJlS2maj4+PePnypcb98uWXXwpDQ0Ph4OAg/P39Rfv27cV3330nhBDi5s2bAoCwtLQUDRs2FF26dBFt2rQRZcqUkc6PhIQEqc4HDx6IoKAgIZfLBQDRuHFjle+k6Ohoqay24/bo0SPpmCs/7506dRIlSpQQAISjo6PaMteuXRMAhL29vQgKChL6+vqiefPmwt/fX1SuXFkAEIaGhuLo0aMqy505c0ZYWFhI+9bPz0906dJFNGrUSJiZmYmaNWu+8Xjm9MsvvwgdHR0BQNSuXVt069ZNuLm5SedHWFiY2jLK4zB8+HBhYWEh7O3thb+/v/D29hbGxsYCgOjQoUO+4hBCiGHDhknnWZMmTURAQICoUqWK0NHREcOHDxcAhKenp9pyurq6wsTERNStW1f4+fkJX19fUaFCBQFAmJqaikOHDqnFr+m7LygoSPz6669Sub59+woAwtnZWbRs2VJ07dpVNGrUSNpfX331lVosy5YtEzKZTMhkMtGgQQPRtWtX4evrK+rUqSN0dXXF8OHD1ZbJz/e68rvb1NRUABCdOnVSif/8+fNv3M/16tUTAMSxY8dUpn/55ZfScX992/bu3SsAiGbNmqlM9/T0FABEbGxsvvev8vM0efJkIZPJhKurqwgICBANGzaU4oiMjHzj9mgyatQoAUCsWbNGCPG/32W5XJ7vupTbXqxYMXHq1CmVeVeuXBF2dnZCJpOJI0eO5LnOd3WdoO23Srk+TZ8fbdd2mo6tEEK8ePFCeHt7CwDCyMhItG7dWnTt2lWUK1dOABAlSpQQ//zzj9b1TJkyRfq97Nq1q3SuyGQy8ccff+R5H+aMcdCgQUJHR0dUqVJFBAQECB8fH+nY5/c6JjU1Vejp6QkLCwvx6tUrlfVVqlRJ2o7NmzerzJs8ebIAIMLDw6Vpe/bsEfr6+tJnoXPnzqJjx46ifv36wtDQUHzxxRf52l4mDojoo6AtcfDixQvpxz8kJETlQv/KlSvCwcFBABATJkzQWJ+mHzGlc+fOafwhTk5OFj4+PgKAmD17ttr8DyVxAEDUr19f5WY1MTFRujGqXr26aN++vUhLS5Pm//XXX0JPT0/o6OiI69evq9T7yy+/SDfA//77r8q8uLg4YW5uLgwMDMSlS5fyvJ253RAX9Ngq9wsA4eXlJVJTU/Mcj5Lyxtba2lotMSGEkC5acq775s2bYs+ePSIrK0ulbFpamggMDJQuLl6n3EZdXV21CwElbftpx44d0sXT7t27Veb99ttvAoDQ19cX//33n8Z15idxEBcXJ93cPXnyRG2Zv/76S2NiRBPlBY6jo2Oeyl+/fl06pvv27ZOm5zzWDRs2FI8ePZLmPX78WLoBDQgIUKnvzp07wtraWshkMjF//nyVY/bw4UPRvHlztQswIf63XwCIcePGqR1rIYR48uSJ2Lx5s9p58/LlSzF+/HgBQLRp00ZtOU37/HXajlvXrl0FANGgQQOVY/D06VPRunVrAUC4ubmpLKNMHCiTBxcvXpTmZWZmij59+kgJlJx69+4tAIjp06erxZeeni7i4uK0xv+606dPCz09PSGTycSKFStU5m3fvl0YGBgIAGrnds7jMHHiRCl5J0R2YkN5U3v48OE8x7Jt2zbpRl+ZsFOaOXOmtD5Nvxlr164Vz549U5mmUCjEzz//LACIqlWrCoVCoTI/t+8+pf3794srV66oTb9w4YKws7PTePPt6OgoAIj4+Hi15e7duydOnDihMq2g3+tv8zun/BzMmDFDLfYyZcoIa2trUb169Twto+3mMi/7V7kN+vr6YuvWrSrzlN8tlpaWIj09PV/bd+jQIaGjo6NyU/Y2iQMhhJg4caKU3PHw8BABAQGiWbNmQl9fX1SoUEFs2bIlX/W9q+uE95E4GDt2rLQvc55/L1++lJJtjo6Oat/ByvUUK1ZMLSGqjLty5cqadpdWyhgBiJ9//lltfkGvYxo1aiQAqCQdlb+DNWrUEADE0KFD37hMs2bNBACxatUqtdhSUlLylWwSgokDIvpIaEscKFsFlClTRuPTf+WTSnNzc/H8+XO1+nJLHOTm4sWLAoCoV6+e2rwPJXEgk8nEmTNn1JZTPlUzMzMT9+7dU5uvfNq+fPlyaVpWVpb0xPTvv//WGM/s2bMFAJUWA2+S28VdQY+tcr/o6+trvOjOi1evXglbW1sBQERFRanMu379uvTEL+eT49ykpaUJPT09YWNjozZPeaz79OmjdXlt+0nZAuDrr7/WuFy7du0EkP2EXNM685M4WL9+vQC0t8LIj5CQEOlmPy9evHghff7XrVsnTc+ZONDU2uH06dNCJpMJHR0dcfPmTWm68sJzyJAhGtd369Ytoa+vL2xsbFRu+JT7pXLlyio3q/lRpkwZoaOjo5Z8KWjiQHk+ymQytRs/5bYon2zlvKDMmTjQdNNx584dAWS3Osh5sdumTRsBQO0GtCCUF/l+fn4a5ytb4bRo0UJlunJfubq6qt2QC/G/82vq1Kl5jkWZDBw7dqzG+coWHfn9zVBezJ89e1Zlel5ubHOzaNEiAUCMHj1aZbqJiYmwtLTMUx1v873+Nr9zyifoTZs2laZduXJF+j3r0qWLACDu3r0rzdfWSqEwEgfavj+dnZ0FALVEUm7S0tJEpUqVhJWVlbh9+7Y0/W0TB0IIsWrVKqnFo/JPT09P9O/fP9+/de/iOkGId584eP78ubQPNH1vpaWliVKlSgkAYvXq1RrX8+OPP6ot9+LFC6mlxY0bN9Tma6OMsXnz5hrnF/Q6Rplcz9niavHixQKAWLJkiShZsqRwdnaW5mlrpVClShUBQCQnJ+d5m3LDPg6I6KOmfPctICAAhoaGavP9/PxgZWWFp0+f4p9//sl3/VlZWdi7dy+mTZuGQYMGoXfv3ggODpbetdb0/uqHonz58qhWrZradGVHhK6urho79VPOz/ku9smTJ3H79m3I5XK4urpqXJ+y/4DDhw+/begA3v7Y1q5dGxUqVCjQuvX09KRhP5csWaIyb+nSpVAoFPD09NQ4bOThw4cxa9YsDB48WDpfBg0aBAMDAzx48EDrO/edO3fOV4yZmZk4dOgQAGh9b1fZ/0JsbGy+6takTp060NXVxZIlS/Dzzz/jzp07b11nXgkhcp1fs2ZN1KpVS2169erVUbt2bSgUCpV3u5XDP3bt2lVjfWXLlkWlSpXw4MEDJCQkqM3v0KEDdHV1c43p33//xZw5czB06FD06dMHwcHBCA4ORmZmJhQKBS5fvpzr8nl14MABKBQK1K5dGzVq1NC4LS1btgSg+TzQ09NDq1at1Kbb2trCysoKGRkZePTokTS9fv36AICBAwdi165db9XXi/Iz/qbzNz4+XmN/Ju3atdM4RKeLiwsAaH3X+XWZmZk4ePAgAKBnz54aywQGBuZax+XLl/HTTz9hxIgR6Nu3r3S87927B6DgvxXPnj1DVFQUJkyYgP79+0v1bty4UWO99evXR2pqKgIDA/HPP/+o9SOQU1F8rwNA48aNYWxsjCNHjiA9PR0ApI5PW7RoAW9vb5VpKSkp+Oeff1CsWDHUrVu30OJQat++vcbp+T2PAGDcuHFISEjA3LlzC63j4levXqFPnz7o2bMnOnTogDNnziAtLQ2XLl3CkCFD8Ouvv6JevXo4depUvusuzOuE9+Hvv//Gs2fPULx4cY3HzcTEBAEBAQC0/+5pWs7Q0FC6XsjP8VbS9vtd0OuY1z8DOf/t4+MDLy8vXLhwQYp1//79yMzMhKenJ/T0/jdoovL7ukePHjh48OBbDwvK4RiJ6KOm/NJ0dHTUOF8mk8HR0RGPHz/O949BQkICOnbsiLNnz2ot83rnNB8SbUMYmZmZ5Trf3NwcAFRuCK5evQoAuHLlisYL9ZwePHiQ71g1edtj+7Zji/fp0wezZs3C7t27kZSUhLJly0IIIXV4pLypUbp//z46deok3YBo8+TJE1hZWb11vI8ePZKOkbZ9JJfLARTsQkhTXZGRkRg9ejSGDBmCIUOGwN7eHo0aNUK7du3QpUsXGBgY5KkuZSdeypuqN7l//770bxsbG7X52rZfOe/EiRO4deuWNE15Pnt4eLxx3Q8ePEDlypVVpuV2rNLS0tCrVy9ER0fnWm9hfXe86XMC5H4elC5dWusoDRYWFnj8+LHKd8Ho0aNx8OBB7NmzB61atYK+vj5q1qyJJk2aICAgAPXq1Su02JVxv3jxAo8ePVK7gdH2HWZhYSEtlxd5+Sxpm56VlYUhQ4Zg0aJFuSa4CnK8t27dit69e6skbt5U7/z589GuXTusXLkSK1eulDr8bN68OXr16qWyz4riex3Ivklzd3dHTEwM4uPj0bJlS+zZswcymQze3t5IS0sDkH2j1KNHD+zbtw8KhQLNmjWDjk7hP/MsrPNo//79+Omnn9CmTZs3JpryY/bs2Vi6dCnatGmDlStXStMrVaqEyMhIPH/+HIsWLcLw4cMRFxeXr7oL8zrhfXjb7zug8I53Ttp+Ewp6HdOoUSOYmpri2LFjePbsGUxNTbFv3z64uLigbNmy8Pb2xu+//449e/YgKChISiooEw5KEREROH36NHbs2IEdO3ZIHX82bdoUPXr0kJJjecXEARGRFp07d8bZs2fRrl07jBkzBlWqVIGFhQX09fXx8uVLjdnjD8mbLrDycwGmfGpla2srPb3U5kMZMtDY2Pitlq9cuTI8PDwQHx+PFStWYPz48YiNjUViYiIsLS3VnjD069cPBw8eRKNGjRAeHo6aNWvCyspKuikrU6YM7ty5o/Xm4m3jLUzanlIOHToU/v7+2LJlCw4ePIiDBw9i7dq1WLt2LUJDQxEfH5+np2zKp5vXrl3DgwcPNCYDcjp+/DiA7HO2du3a+dyabDn3u3L7OnfuDFNT01yXs7a2VpuW27EaP348oqOj4ezsjG+++Qb16tVDiRIlpKSKm5sbjhw58sZWFO9Lfm/ETExMEBMTg7/++gs7d+7E4cOHcfjwYfz999+YM2cOBg0ahJ9//vkdRavqXdxE5tcPP/yAhQsXwtbWFnPmzIGbmxtKlSol9YTfvXt3/P777/k+3klJSejatSueP3+OMWPGoEePHnBwcICZmRl0dHSwe/dutGzZUq1eFxcXXLx4Ebt378a+fftw+PBhxMfHY9++fZg6dSoWL14staooyu91b29vxMTEICYmBj4+Pti3bx+qV6+OUqVKAci+0VLeDGm7KSoshXUebdq0CUII3LhxQ20EH+WoOklJSdK8uXPnamwp9Tplsrpbt24a53fv3h2LFi3CwYMHkZGRka9rk8K8TvhYvIttKuzfb319fTRp0gQ7duzA/v37Ub58edy7d09qJaf8LMTExOSaOLC1tcXff/+NuLg47NmzB4cOHcKxY8dw6NAhzJw5ExERERg7dmye42LigIg+amXLlgXwvycnmly7dk2lbF5cuHABp0+fRsmSJREdHa3S9AuAxubLn7Jy5coByL6Jen2IvnflXR3b/Ojbty/i4+OxdOlSjB8/XnptISAgQOVCIS0tDdu3b4eOjg62b9+OYsWKqdSTlpaGu3fvFmps1tbWMDQ0REZGBq5evaqxmbpy372+f5Q3sU+fPtVYt3KoNU1KlSqFL7/8El9++SWA7M9Knz59cOTIEYwbN04aVjA3zZs3h7m5OZ4+fYoVK1Zg5MiRuZZXDovm4eGhtm+B/50HmiiHLrSzs5OmlStXDgkJCRg7dmyhN31WDpO3bt06jceksL878vI50XYevI169epJrQsyMzOxadMmBAYGYv78+ejcubM05G1uypYtiytXruDq1asam0sr4zYyMkLx4sULLfbX5fwsJSYmomrVqmpltA1dqjzeixYt0jh8WkGP99atW/H8+XN07NgRs2bNyle9enp6aNOmDdq0aQMgu1XCnDlzEB4ejgEDBqBjx44wNTUtku91pZxNsU+ePIlHjx5Jr4cp5//666+4cOHCO08cFLb//vtP67wXL15IrQK0DdH7uhs3bgD43xPx11laWgLITgSlpKRIyZdPkfI7LLfv/HfxfVdQb3Md4+3tjR07dmDPnj1SKwnlZ6B8+fKoVKkS9u7di6SkJJw/fx5lypRBlSpV1OpXDrupTFi9ePECy5Ytw+DBgzFhwgR07txZaqXxJp9eGomIPivKL8J169ZpbF4WHR2Nx48fw9zcXOUdTuWNk7b3vZTj0ZcpU0YtaQAAq1atetvQPyrKp6bnzp3L9dWNwlTQY1uYunTpAgsLCyQkJGDbtm34448/AKi/ppCamoqsrCxYWFhovLFdtWpVoT9h1tPTg7u7OwBovehXJjpev4lTXqCcP39ebZm7d+/ixIkTeY7D2dlZemKR13dsLSwsMHjwYADA9OnTc01UbNu2DVu3bgUATJgwQWOZ06dP4/Tp02rTz549ixMnTkBHR0dlbOvWrVsD+N9NX2FSfnfY29urzdu1axcePnyocbk3fSdp06RJE+jo6ODUqVP4999/1ebfuXMHO3fuBKB+HhQWPT09dO7cWXpqndfzQPkZf9P56+HhofF7uLDo6emhcePGAIDVq1drLJOziXhOuR3vs2fPat0Xef0N0lSvEAJr1qzRuJwmFhYWCAsLQ7FixZCeno5Lly4BeLvv9YKer0q1a9eGtbU1Tp8+LW1LixYtpPnKG6TFixcjISEB5cqVU3tl6F3GVxBz586FyO54Xu1P+b69XC6Xpr3eKkEb5ff1sWPHNM4/evQogOzXBz6UFn/vSt26dWFmZobk5GRs2bJFbf7z58+xdu1aAO/u+y4/3uY6Jmergj179kBPT0/lnPH29sbdu3cxd+5cAICXl1eeYjIyMkJISAhq1KgBhUKh8bdTGyYOiOij1qVLF5QvXx63b9/G119/rXKRcO3aNelJ5tChQ6Wmo8D/nj4mJCTg1atXavVWrlwZurq6OHPmjNS5jdLWrVsRGRn5Drbmw6Wvr4/Q0FAIIdCxY0eN7/FnZWVh37590kXM2yrosS1MJiYmUvPQPn364Pnz56hevbrae9ylSpWClZUVUlJS1G4wjh49ivHjx7+T+JT7YMGCBdi7d6/KvGXLlmHLli3Q19fH8OHDVeYpL0hmzZql8tTrwYMHCAwMxLNnz9TWtW/fPmzfvl3t8yKEwLZt2wBovsnRJiwsDHXr1kVKSgqaNWum1vmaEAKrVq2SmmYOHToUPj4+GusSQmDgwIEqHU+mpqZi4MCBEEKgU6dO0tNVIPs9/WLFimHOnDn4/vvv8fLlS7U6r127VqAEofKd0Xnz5qlMv3jxIkJCQrQup/xOyu8NXPny5dGlSxcIITBgwACV9+HT0tLQv39/vHjxAm5ubnBzc8tX3ZrMnz9fY0d/d+/exd9//w0g7+fB8OHDoaenh02bNqnt6927d2PRokUAgFGjRr1l1G82YsQIANnH7fVzcfbs2VqTacrj/fPPP6u84nPnzh0EBgZqvXF90/FW1rthwwaVjkizsrIwZcoUjZ0VpqenY86cORr7I4iPj0dKSgp0dXWldb/N93pBz1clmUyG5s2bQwiBn3/+GQYGBirJPS8vL8hkMvz0008A8t/a4G3je9+SkpLg7OwMZ2dntXfzla/FRUZGql2PnDp1CpMnTwYA+Pv7v7HT1o+dkZGRlHQeOXKkStL51atXGD58OO7evQtHR8d8dzj8LrzNdUz16tVRsmRJnDt3DrGxsWjYsKHUtwTwv89Ebp+R7777TmqxktOFCxekVkv5+d3mcIxE9FHQNhyjEEIcP35cFC9eXADZ45F37dpVtGnTRhqCrGXLlmrj+QohRN26dQUA4eTkJHr06CH69u2rMhTX8OHDBf5/3GRPT0/RrVs3UadOHQFATJo0SWs8H8pwjNqGDdO2nFJuw1iNHj1a2u6qVauKL774QgQEBIimTZuKYsWKCQBiwYIFedvIN6xLiIId2zdtX34dP35cZfiruXPnaiwXGRkplWnQoIHo1q2baNy4sZDJZKJXr15az4u8nC+57SfluSiTyYS7u7vo3r27dJ7q6uqKxYsXqy3z+PFjab0lS5YUX3zxhfD29haWlpaievXqokOHDmrnn3L7LCwsRNOmTUX37t1Fx44dpXosLS01DomYm5SUFNGqVStpv1WvXl34+/uLjh07SuPU6+joiDFjxmgcdk95rH19fUWFChVEsWLFRMeOHYWfn5903lSqVEnjcGJxcXGiRIkS0j5o3ry56NGjh2jXrp2Qy+XSccwpL0Mmbty4UchkMml7AgICRPPmzYW+vr5o3ry5cHNz0zh83L///it0dHSEjo6O8Pb2Fr179xZ9+/YVmzdvlspoO1cePnwoatasKR2HDh06iM6dOwsbGxsBZI9p/voyyuEY7e3ttW6LpvUp1+Po6Cjat28vevToIXx8fISxsbE0LFnO4cDeZNGiRdLwpnXq1BHdu3eXPjd4bTgypTcdh4J+BwwePFg655o2bSq6desmqlatKnR0dKTfg9e/V48ePSoMDAwEAFGxYkXh7+8vWrVqJYyNjUXVqlVFx44dNcZ69+5dYWpqKgCIxo0bi+DgYNG3b1+xZMkSIUT2kLCurq7SkHht27YV/v7+wt7eXujr60tDiuaM5/Hjx1L8NWvWFJ07dxbdunUTjRo1kvbnlClT1La7IN/rP/30kxSbn5+f6Nu3r+jbt6+4cOFCnve3ckhJAKJZs2Zq82vXri3Nf31oPSVtwzG+af8KUbBhaQvqTcMx5hwe9fV4njx5Ig1HCWQPA+3v7y/c3NyErq6u9F3z8OHDfMdT2NcJ73o4RiGyh05UDkVsbGws2rRpI7p27SrKly8vAAhra2uNw4tqW8+b1pebvCxT0GtUIYTo1q2bFHd4eLjKvMePH0vfnQBEUlKS2vLKISadnZ1Fx44dRffu3UXTpk2Fnp6eACACAwPzvK1CZDeVISL64OWWOBBCiBs3bojBgweLChUqCAMDA2Fubi4aNWokFixYoPUi9vr166J79+6idOnS0pdozotohUIhFi9eLFxdXYWZmZmwtLQU7u7uYu3atUII7T9Cn3LiQAghDh06JHr06CHs7e2FoaGhMDc3F5UrVxYdOnQQv/32W77GC87LWNv5PbaFnTgQQojq1asLAMLAwCDXi7NNmzYJNzc3UaxYMWFmZibq1q0r5s+fLxQKxTtLHAghxI4dO0SbNm2EtbW10NPTE7a2tqJLly5qY57ndOvWLREYGChKliwpDAwMhKOjoxg9erR4+vSpxgvmy5cvi7CwMOHl5SXKly8vjIyMhJWVlahRo4YYN26cuHnzptZ1vcmff/4pAgICpHrNzMyEk5OTGDhwoDh9+rTW5XIe6/v374sBAwYIOzs7YWBgIMqVKyeGDRsmHj16pHX5e/fuicmTJ4s6deoIc3NzYWBgIOzs7ISbm5sIDQ1VW3debyQOHDggvLy8RIkSJYSJiYmoVq2amDFjhsjIyMj1QjM6Olo0btxYmJubSzd6OY95budKWlqaiIiIELVq1RImJibCyMhIuLi4iAkTJmj8TBY0cbBt2zYxcOBAUbt2bWFjYyPts6ZNm4rly5eLly9f5rpvNDl69Kjo3LmzsLW1FXp6esLa2lq0bdtW7N69W2P5d5U4EEKIJUuWCFdXV2FkZCQsLS2Ft7e3iI2NzfV79fTp08LX11eULl1aGBkZiUqVKokxY8aIJ0+e5BrrgQMHhLe3t7CyspJuAHLG/PTpUzFhwgTh5OQkjIyMRMmSJUWHDh3E33//rTGeV69eiYULF4pu3boJZ2dnYWlpKYyNjYVcLhedOnUSe/fu1brd+f1ez8rKEhEREaJq1arSDVB+b7quXLkiLTdjxgy1+cqEhkwmE3fv3tVYR26fpzft348lcSCEEBkZGeKHH34Q7u7uwsrKSujq6goLCwvRsGFD8e2334r09PQCxfMxJg6EyD7X58+fLxo2bCh9d8vlcjF06FBx69YtjTEXVeJAiIJdowohxOLFi6W4Dx06pDZfmVBycXHRuPyqVatE7969RbVq1UTx4sWFoaGhsLe3F61btxbR0dEaE/K5kQnxgXTrS0RERJQPy5YtQ+/evREUFPTeO3cjIiL6nLCPAyIiIiIiIiLSiokDIiIiIiIiItKKiQMiIiIiIiIi0op9HBARERERERGRVmxxQERERERERERaMXFARERERERERFrpFXUARESfGoVCgdu3b8Pc3BwymayowyEiIiKid0AIgadPn6JMmTLQ0fm0n8kzcUBEVMhu376NcuXKFXUYRERERPQe3Lx5E3Z2dkUdxjvFxAERUSEzNzcHkP0jYmFhUcTREBEREdG78OTJE5QrV0669vuUMXFARFTIlK8nWFhYMHFARERE9In7HF5N/bRfxCAiIiIiIiKit8LEARERERERERFpxcQBEREREREREWnFxAERERERERERacXEARERERERERFpxcQBEREREREREWnFxAERERERERERacXEARERERERERFpxcQBEREREREREWnFxAERERERERERacXEARER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+tiwc0QiokLGzhGJiIiI3i92jvhusXNEIiIiIiIiItKKiQMiIiIiIiIi0oqJAyIiIiIiIiLSiokDIiIiIiIiItKKiQMiIiIiIiIi0oqJAyIiIiIiIiLSiokDIiIiIiIiItJKr6gDICL6VJXu/umP6UtEREREnz62OCAiIiIiIiIirZg4ICIiIiIiIiKtmDggIiIiIiIiIq2YOCAiIiIiIiIirZg4ICIiIiIiIiKtmDggIiIiIiIiIq2YOCAiIiIiIiIirZg4ICIiIiIiIiKtmDggIiIiIiIiIq30ijoAIqJPleW6JYCx8Xtbn+g54L2ti4iIiIg+H2xxQERERERERERaMXFARERERERERFoxcUBEREREREREWjFxQERERERERERaMXFARERERERERFoxcUBEREREREREWjFxQERERERERERaMXFARERERERERFoxcUBEREREREREWjFxQERERERERERaMXFARERERERERFoxcUBEREREREREWjFxQERERERERERaMXFACA4OhoODwztf5m04ODggODj4va3vY9O0aVM0bdq0qMMgIiIiIqJPEBMH+RAcHAyZTKb1LykpqahD/CjMnDkTmzZtUpt++PBhhIWFISUl5b3H9KG4ffs2wsLCcOrUqaIO5YOmUCiwbNky+Pr6oly5cjA1NUW1atUwffp0vHjxQuMyixcvhouLC4yMjFCpUiXMmzfvjetp0aIFZDIZhgwZUtibQERERET00dAr6gA+JgMGDIC3t7fKNCEEQkJC4ODggLJlyxZRZB+XmTNnonPnzujQoYPK9MOHDyM8PBzBwcEoVqyYyryLFy9CR+fTz3Pdvn0b4eHhcHBwQK1atfK83O7du99dUB+g9PR09O7dGw0bNkRISAhKliyJI0eOIDQ0FHv37sW+ffsgk8mk8osWLUJISAg6deqEr7/+GvHx8Rg2bBjS09MxduxYjev4448/cOTIkfe1SUREREREHywmDvKhUaNGaNSokcq0gwcPIj09HT169Ci09aSlpcHU1LTQ6vsUGBoaFnUIH6T09HSYmJjAwMCgqEN5rwwMDHDo0CG4ublJ07788ks4ODhIyQNlku/58+eYOHEi2rZtiw0bNkhlFQoFpk2bhv79+8PKykql/hcvXmDkyJEYO3YspkyZ8v42jIiIiIjoA/TpP8J9x9asWQOZTIbu3bsX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IiKiXDBxQERERERERERaMXFARERERERERFoxcUBEREREREREWjFxQERERERERERaMXFARERERERERFrpFXUARESfqtSufT75MX2JiIiI6NPHFgdEREREREREpBUTB0RERERERESkFRMHRERERERERKQVEwdEREREREREpBUTB0RERERERESkFRMHRERERERERKQVEwdEREREREREpBUTB0RERERERESkFRMHRERERERERKSVXlEHQET0qbpT0wbPdGRFHQa9hTJXXhR1CERERERFji0OiIiIiIiIiEgrJg6IiIiIiIiISCsmDoiIiIiIiIhIKyYOiIiIiIiIiEgrJg6IiIiIiIiISCsmDoiIiIiIiIhIKyYOiIiIiIiIiEgrJg6IiIiIiIiISCsmDoiIiIiIiIhIKyYOiIiIiIiIiEgrJg6IiIiIiIiISCsmDoiIiIiIiIhIK713Uem1a9dw+vRp2Nvbo1atWu9iFURERERERET0HhS4xcGWLVvg5+eH48ePq0z/9ttvUblyZfj5+cHV1RV9+vR56yDp4xMcHAwHB4d8L7dy5Uo4OztDX18fxYoVAwA0bdoUTZs2lcokJiZCJpNh2bJlhRLru/axxZsb5bZ89913RR2KxMHBAe3atSvqMIiIiIiIPlkFThysWLECO3fuhIuLizTtwoULGDduHIQQqFmzJkxMTLB8+XJs3bq1UIL9lJ04cQK+vr4oXrw4TExMUK1aNfz4449FHdZ7deHCBQQHB0Mul+PXX3/FL7/8kudlt2/fjrCwsHcXHL0zhw8fRlhYGFJSUoo6FCIiIiIi0qDAiYOTJ0+iZs2aMDc3l6atXr0aADB//nycOHECf/31F3R1dfN1A/g52r17Nxo1aoT79+9j8uTJ+OGHH9CuXTvcunWrqEN7r/bv3w+FQoEffvgBwcHB8Pf3B5C9f3bv3p3rstu3b0d4ePj7CJMK2eHDhxEeHs7EARERERHRB6rAfRw8fPgQtWvXVpm2f/9+GBsbIzg4GADg7OwMd3d3nD179q2C/JQ9efIEgYGBaNu2LTZs2AAdnXfTX2VaWhpMTU3fSd2F5f79+wAgvaKgZGBgUATRAEIIvHjxAsbGxkWyfiIiIiIiog9Bge9SX7x4AV1dXen/WVlZOHHiBBo0aKByo1emTBncvXv37aL8hK1Zswb37t3DjBkzoKOjg7S0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r17FwoUL0bFjR1hZWeXq+IiIiIiIiiImDqhIOX/+PABgx44d2LFjh8b6zKb6y4n+/fvD0dERc+bMwbx585Camopy5crB09MTQ4YMkeqtXbsWY8aMwaJFiyCEgLe3N3bu3Kkx9kKtWrUQERGBiRMnYvr06ShfvjyCg4Px8OHDbCUOnJyc0K9fP+zbtw+rVq2CkZERqlWrhg0bNqBHjx5qdStXrowFCxZgypQpuH79OlxdXbF+/Xq1mRxKlCiBgwcPYvbs2di4cSNWrlwJa2trVKlSBcHBwWozDyxfvhy1atXCsmXLMGXKFMjlcjRo0ABNmzbN7unV6tNPP4WdnR3mzJmDGTNmwNjYGNWqVcOECRNy1e7w4cORkZGBefPmYcqUKahZsya2b9+Ob775Rq2ev78/1qxZgx9++AHPnz9H+fLlMXbsWHz99de52j8RERERUVElE3nRv5iICiUXFxfUqFEDf/31l75DKVaSk5PfJFuW/gi8M+gmERER0YdMDPTXdwgFRvU3n0KhUJtx7UPEMQ6IiIiIiIiISCe+qkBUyCgUCrx69SrTOtqmhywOXr16BYVCkWmdUqVKwcTEpIAiIiIiIiL68DFxQFTIjBs37r2DABbXN4zWr1+vNraENgcOHECrVq0KJiAiIiIiomKAiQOiQmbq1Kl5NshjTExMnrRTWPj4+GDPnj2Z1qldu3YBRUNEREREVDwwcUBUyLi7u8Pd3V3fYRRKDg4OcHBw0HcYRERERETFCgdHJCIiIiIiIiKdmDggIiIiIiIiIp2YOCAiIiIiIiIinZg4ICIiIiIiIiKdmDggIiIiIiIiIp2YOCAiIiIiIiIinZg4ICIiIiIiIiKdjPQdABHRh0rRZyisra31HQYRERERUa6wxwERERERERER6cTEARERERERERHpxMQBEREREREREenExAERERERERER6cTEARERERERERHpxMQBEREREREREenExAERERERERER6cTEARERERERERHpxMQBEREREREREelkpO8AiIg+VA9r2+K5gUzrOsdbKQUcDRERERFRzrDHARERERERERHpxMQBEREREREREenExAERERERERER6cTEARERERERERHpxMQBEREREREREenExAERERERERER6cTEARERERERERHpxMQBEREREREREenExAERERERERER6cTEARER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D6mpqShXrhw8PT0xZMgQqd7atWsxZswYLFq0CEIIeHt7Y+fOnXB0dFRrr1atWoiIiMDEiRMxffp0lC9fHsHBwXj48GG2EgdOTk7o168f9u3bh1WrVsHIyAjVqlXDhg0b0KNHjzw59tGjR0MIge+//x6TJ09G7dq1sX37dowdOxZmZmaZbuvu7o7Tp08jODgY4eHhiI+Ph52dHerWrav2OkdWfPvtt3B1dcWCBQvw1VdfoUSJEqhVqxYGDRok1QkKCoKtrS0WLlyICRMmoFSpUhg+fDhmz54NY2PjTNtfsGABXr9+jV9++QWmpqbo3bs35s2bhxo1amQrTiIiIiIiyhmZyIvR1oioUFAqlbC1tUX37t3x66+/6jucYis5ORlyuRzXXExgZaC994fjrRSt5URERERUNKj+5lMoFLC2ttZ3OPmKYxwQFVEpKSka4zasXLkSCQkJaNWqlX6CIiIiIiKiDw5fVSDKJoVCgVevXmVaR9v0kHntxIkTmDBhAnr16oXSpUvj7NmzWLZsGWrUqIFevXrluv1Hjx5lut7c3DxPXzshIiIiIqLCiYkDomwaN24cVqxYkWmdgngDyMXFBU5OTvj555+RkJCAUqVKYfDgwZgzZw5MTExy3b6Dg0Om6319fREeHp7r/RARERERUeHGMQ6IsunKlSvSjBG6eHl5FVA0+Wfv3r2Zrnd0dIS7u3sBRVO0cIwDIiIiog9fcRrjgIkDIqI8xsQBERER0YevOCUOODgiEREREREREenExAERERERERER6cTEARERERERERHpxMQBEREREREREenExAERERERERER6cTEARERERERERHpxMQBEREREREREelkpO8AiIg+VA4X4j74OX2JiIiI6MPHHgdEREREREREpBMTB0RERERERESkExMHRERERERERKQTEwdEREREREREpBMTB0RERERERESkExMHRERERERERKQTEwdEREREREREpBMTB0RERERERESkExMHRERERERERKQTEwdEREREREREpBMTB0RERERERESkExMHRERERERERKQTEwdEREREREREpBMTB0RERERERESkExMHRERERERERKQTEwdEREREREREpBMTB0RERERERESkExMHRERERERERKQTEwdEREREREREpBMTB0RERERERESkExMHRERERERERKSTkb4DICL6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",
      "text/plain": [
       "<Figure size 1000x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "xlabel_size = 16\n",
    "ylabel_size = 16\n",
    "title_size = 16\n",
    "xtick_size = 14\n",
    "ytick_size = 12\n",
    "\n",
    "inset_xtick_size = 10\n",
    "inset_ytick_size = 10\n",
    "inset_title_size = 12\n",
    "\n",
    "labels = task_benchmark_dict[\"task_names\"]\n",
    "times = task_benchmark_dict[\"task_times\"]\n",
    "# Create the main plot with numbered x labels and an inset showing the same data on a log scale\n",
    "fig, ax = plt.subplots(figsize=(10, 6))\n",
    "\n",
    "# Number the labels\n",
    "numbered_labels = [f\"{i+1}. {label}\" for i, label in enumerate(labels)]\n",
    "\n",
    "# matplotlib_utils.set_palette('Cavalcanti1')\n",
    "matplotlib_utils.set_palette(\"Darjeeling1_alt\")\n",
    "# matplotlib_utils.set_palette('Zissou1')\n",
    "# matplotlib_utils.set_palette('AsteroidCity1')\n",
    "# matplotlib_utils.set_palette('BottleRocket2')\n",
    "colors = rcParams[\"axes.prop_cycle\"].by_key()[\"color\"]\n",
    "# Main horizontal bar plotcolors[:len(times)]\n",
    "# ax.barh(numbered_labels, times, color=\"#59b9de\")\n",
    "ax.barh(numbered_labels, times, color=colors[: len(times)])\n",
    "ax.set_xlabel(\"Total Time (seconds)\", fontsize=xlabel_size)\n",
    "ax.set_ylabel(\"Operations\", fontsize=ylabel_size)\n",
    "\n",
    "ax.tick_params(axis=\"x\", labelsize=xtick_size)\n",
    "ax.tick_params(axis=\"y\", labelsize=ytick_size)\n",
    "ax.set_title(\n",
    "    \"Total Time for Various Operations on dataset with 4.8 million rows\",\n",
    "    fontsize=title_size,\n",
    ")\n",
    "\n",
    "# Inset plot with log scale and just the numbers\n",
    "# ax_inset = inset_axes(ax, width=\"40%\", height=\"30%\", loc=\"center right\")\n",
    "\n",
    "ax_inset = inset_axes(\n",
    "    ax,\n",
    "    width=\"30%\",\n",
    "    height=\"30%\",\n",
    "    loc=\"center right\",\n",
    "    bbox_to_anchor=(-0.05, -0.1, 1, 1),\n",
    "    bbox_transform=ax.transAxes,\n",
    ")\n",
    "ax_inset.barh(range(1, len(labels) + 1), times, color=\"#e52207\")\n",
    "ax_inset.barh(range(1, len(labels) + 1), times, color=colors[: len(times)])\n",
    "ax_inset.set_xscale(\"log\")\n",
    "ax_inset.set_yticks(range(1, len(labels) + 1))  # Show just the numbers\n",
    "ax_inset.set_yticklabels(range(1, len(labels) + 1), fontsize=inset_ytick_size)\n",
    "ax_inset.set_title(\"Log Scale\", fontsize=inset_title_size)\n",
    "\n",
    "# Adjust layout and show the plot\n",
    "plt.tight_layout()\n",
    "\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "parquetdb_dev",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.20"
  },
  "nbsphinx": {
   "execute": "never"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
